Frobby
0.9.5
src
ElementDeleter.h
Go to the documentation of this file.
1
/* Frobby: Software for monomial ideal computations.
2
Copyright (C) 2007 Bjarke Hammersholt Roune (www.broune.com)
3
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or
7
(at your option) any later version.
8
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
13
14
You should have received a copy of the GNU General Public License
15
along with this program. If not, see http://www.gnu.org/licenses/.
16
*/
17
#ifndef ELEMENT_DELETER_GUARD
18
#define ELEMENT_DELETER_GUARD
19
20
// The purpose of this class is to call delete on the elements of a
21
// standard library container which holds pointers. It removes the
22
// elements from the container as they are being deleted, but it does
23
// not delete the container itself. Do not use this class to
24
// deallocate a vector of built-in arrays, since those require
25
// deallocation using delete[] rather than delete.
26
//
27
// This can be a convenience when coding, but the real purpose is to
28
// avoid memory leaks in the face of an exception being thrown. When a
29
// standard library container goes out of scope, its destructor is
30
// called, but the destructor does not deallocate pointer elements, so
31
// they will leak unless special care is taken to aovid that, such as
32
// using this class.
33
//
34
// The most straight-forward solution may seem to use
35
// e.g. vector<auto_ptr<T>> in place of vector<T*>, but this does not
36
// work because storing auto_ptr<T> in a standard library container is
37
// never safe (look this up on the internet to get the details).
38
//
39
// The reference counting smart pointer class shared_ptr from Boost or
40
// TR1 would solve this issue even better by using
41
// vector<shared_ptr<T>> instead of vector<T*>, but that would require
42
// a dependency on Boost or on having a very recent compiler which
43
// incorporates TR1.
44
//
45
// TODO: make an AutoVector that wraps std::vector instead of or as a
46
// supplement to this class.
47
//
48
// Container::value_type is required to be a pointer type.
49
template
<
class
Container>
50
class
ElementDeleter
{
51
public
:
52
// Only the constructor can attach an ElementDeleter to a container,
53
// and this helps ensure (but does not guarantee) the precondition
54
// of the destructor of ElementDeleter.
55
ElementDeleter
(Container&
container
):
_container
(&
container
) {
56
}
57
58
// Calls deleteElements() and shares its precondition.
59
~ElementDeleter
() {
60
deleteElements
();
61
}
62
63
// Call release() to prevent this ElementDeleter from manipulating
64
// the container in any way.
65
void
release
() {
66
_container
= 0;
67
}
68
69
// If release has been called, this method does nothing. Otherwise
70
// the container must still be valid, and then delete is called on
71
// each element of the array and clear is called on the container.
72
void
deleteElements
() {
73
if
(
_container
== 0)
74
return
;
75
76
// The code below may seem obviously correct, but it is a
77
// non-trivial fact that it works in the face of exceptions.
78
//
79
// First of all, we are allowed to assume that destructors do not
80
// throw exceptions, so the loop will run to completion.
81
//
82
// Normally clear() *can* throw an exception according to the
83
// standard (which is weird), but if the copy constructor and
84
// assignment operator do not throw exceptions, then it does
85
// not. In our case, we require the element type to be a pointer
86
// type, so for this reason only do we know that clear will not
87
// throw an exception. Thus we do not have to worry about leaving
88
// around a container full of invalid pointers if clear() should
89
// throw an exception.
90
91
typename
Container::iterator end =
_container
->end();
92
typename
Container::iterator
it
=
_container
->begin();
93
for
(;
it
!= end; ++
it
)
94
delete
*
it
;
95
_container
->clear();
96
}
97
98
private
:
99
Container*
_container
;
100
};
101
102
// exceptionSafePushBack is designed to work around the fact that this
103
// code can leak memory:
104
//
105
// vector<int*> vec;
106
// ElementDeleter<vector<int*> > elementDeleter(vec);
107
// auto_ptr<int> p(new int());
108
// vec.push_back(p.release())
109
//
110
// This is because push_back can fail by throwing a bad_alloc, and at
111
// that point the pointer in p has already been released, so that
112
// pointer is now lost and hence the memory is leaked.
113
//
114
// This can be fixed by replacing
115
//
116
// vec.push_back(p.release())
117
//
118
// by
119
//
120
// vec.push_back(0);
121
// vec.back() = p.release();
122
//
123
// but this is annoying and looks quite strange. It is much clearer to
124
// write
125
//
126
// exceptionSafePushBack(vec, p);
127
//
128
template
<
class
Container,
class
Element>
129
void
exceptionSafePushBack
(Container&
container
,
auto_ptr<Element>
pointer) {
130
container
.push_back(0);
131
container
.back() = pointer.release();
132
}
133
134
// Serves the same purpose as exceptionSafePushBack, except that this
135
// overload will simply ignore an exception without propagating it.
136
// Thus if there is not enough memory to add the element to the container,
137
// the element will simply get deleted and the container will remain
138
// unchanged. This works well if e.g. adding an element to a cache, where
139
// it is no great problem if the element gets deleted rather than added.
140
template
<
class
Container,
class
Element>
141
void
noThrowPushBack
(Container&
container
,
auto_ptr<Element>
pointer)
throw
() {
142
try
{
143
exceptionSafePushBack
(
container
, pointer);
144
}
catch
(
const
bad_alloc
&) {
145
// Ignore the exception.
146
}
147
}
148
149
#endif
noThrowPushBack
void noThrowPushBack(Container &container, auto_ptr< Element > pointer)
Definition
ElementDeleter.h:141
exceptionSafePushBack
void exceptionSafePushBack(Container &container, auto_ptr< Element > pointer)
Definition
ElementDeleter.h:129
nameFactoryRegister
void nameFactoryRegister(NameFactory< AbstractProduct > &factory)
Registers the string returned by ConcreteProduct::getStaticName() to a function that default-construc...
Definition
NameFactory.h:142
ElementDeleter
Definition
ElementDeleter.h:50
ElementDeleter::deleteElements
void deleteElements()
Definition
ElementDeleter.h:72
ElementDeleter::release
void release()
Definition
ElementDeleter.h:65
ElementDeleter::ElementDeleter
ElementDeleter(Container &container)
Definition
ElementDeleter.h:55
ElementDeleter::~ElementDeleter
~ElementDeleter()
Definition
ElementDeleter.h:59
ElementDeleter::_container
Container * _container
Definition
ElementDeleter.h:99
Generated by
1.9.8