Adding pointer to container

T

tech

Hi, i have a std::vector of pointers to base classes say
std::vector<element*> m_elements;
how do i make the followin exception safe

function()
{
element* e= new DerivedElement;
m_elements.push_back(element);
}

the push back operation can throw so i can leak element if it throws
i thought of doing this but it still has the same problem as e.get()
gets executed first
then if the push back throws i leak the pointer. How to solve?? I
can't use
Boost on this project so the shared_ptr is not an option

function()
{
std::auto_ptr <element> e(new DerivedElement);
m_elements.push_back(e.get());
}
 
I

Ian Collins

tech said:
Hi, i have a std::vector of pointers to base classes say
std::vector<element*> m_elements;
how do i make the followin exception safe

function()
{
element* e= new DerivedElement;
m_elements.push_back(element);
}

the push back operation can throw so i can leak element if it throws
i thought of doing this but it still has the same problem as e.get()
gets executed first
then if the push back throws i leak the pointer. How to solve?? I
can't use
Boost on this project so the shared_ptr is not an option
Then roll your own simple shared_ptr pointer.
 
T

tech

You could do something like:

function()
{
   std::auto_ptr <element> e(new DerivedElement);
   m_elements.push_back(e.get());
   e.release();



}- Hide quoted text -

- Show quoted text -- Hide quoted text -

- Show quoted text -

Replying to Chris Thomasson
std::auto_ptr <element> e(new DerivedElement);
m_elements.push_back(e.get());
e.release();

But this is what i had above without the e.release() at the
bottom, if m_elements.push_back(e.get()); this throws
as the e.get() has already given up the pointer then if the
push back throws surely i will leak the pointer.
Or are you saying the e.get() returns a copy of the pointer
and the auto_ptr still hangs onto it. In that case
it would work and thanks to you
 
D

Daniel Pitts

Alf said:
* Paavo Helde:

If DerivedElement constructor throws, has already added nullpointer to
vector.


Cheers, & hth.,

- Alf
How about using a try/catch.
void function() {
element * d = new DerivedElement;
try {
m_elements.push_back(d);
} catch (...) {
delete d;
throw;
}
}
 
R

Roland Pibinger

Hi, i have a std::vector of pointers to base classes say
std::vector<element*> m_elements;
how do i make the followin exception safe

function()
{
element* e= new DerivedElement;
m_elements.push_back(element);
}

You question includes more than one aspect:

1. STL is designend for values only (a.k.a. 'value semantics'), not
objects or pointers to objects. Put simply, STL doesn't work with
pointers.

2. You cannot practically 'handle' Out-Of-Memory (OOM). You can do it
in theory but it always boils down to terminating the application.
Therfore you need not care for OOM conditions or even try to catch
std::bad_alloc in your application code. Some OS (e.g. Linux) never
indicate OOM.

3. If you still want an 'exception safe' push_back() for vector use
reserve() to 'pre-order' enough capacity. Something like the following
(BTW, note the difference between reserve() and resize()):

if (vec.capacity() == vec.size()) {
vec.reserve(vec.capacity() * 2);
}
vec.push_back(new Element());
 
R

Roland Pibinger

* Roland Pibinger:

Well I think I've written something like that in the past.

Well, some years ago I thought that you could handle OOM ...
But it's wrong.

Think about an application where the user attempts to load a very big image
file. If allocation fails, a good way to handle it is to inform the user that
sorry, that file was too big. A bad way to handle it would be to terminate...

In case of a file you know the file size in advance and know if the
size is within the limits of your function contract. The Java language
distinguishes between (recoverable) Exceptions and (fatal) Errors.
What can you do after OOM? Can you recover vital memory to proceed?
Hardly in practice. IMO, OOM is a fatal error (like stack overflow and
memory corruption) that should lead to more or less abrupt termination
of the program. This also means that you need not write your code as
if std::bad_alloc were a recoverable exception.
 
D

Daniel Pitts

Roland said:
Well, some years ago I thought that you could handle OOM ...


In case of a file you know the file size in advance and know if the
size is within the limits of your function contract. The Java language
distinguishes between (recoverable) Exceptions and (fatal) Errors.
What can you do after OOM? Can you recover vital memory to proceed?
Hardly in practice. IMO, OOM is a fatal error (like stack overflow and
memory corruption) that should lead to more or less abrupt termination
of the program. This also means that you need not write your code as
if std::bad_alloc were a recoverable exception.
OOM being fatal depends on the context, in both Java *and* C++. In
Java, it is rare, but not unheard-of to recover from an OOM. in C++ it
would probably be easier to recover, since you have more control over
the deallocation of memory than you do in Java.

Like someone said, you can report to the user that the particular
operation took too much memory, and to try another operation instead.
This is better than, say, crashing an entire photo editing session
(probably without saving) because they tried to open one-to-many large
photos.

Now, if it were a small program used in a form of batch processing,
"dieing" on OOM makes more sense, depending on the level of severity of
the operation that can't be completed.
 
K

Kai-Uwe Bux

Paavo said:
(e-mail address removed) (Roland Pibinger) kirjutas:


It seems this is so ridiculous no one has bothered to answer. For innocent
bystanders I just remind that pointers are values in C++.

It is true, though, that pointers often require special handling when
dealing with containers. The most basic issue is illustrated by

std::map< char const *, some_type >

By default, the map will compare pointer values and not the strings they
represent. Very likely that is _not_ the desired behavior.


Best

Kai-Uwe Bux
 
K

Kai-Uwe Bux

Paavo said:
If you specify the map keys as pointers, they will be compared as
pointers, that's it.

Actually, nobody knows how they are compared. [20.3.3/8] just requires
std::less<T*> to yield a total order. There is no requirement whatsoever
that this order is related to or compatible with pointer comparison as per
[5.9/2].
I see nothing specific to STL here.

Huh? How is the default behavior of STL containers not specific to STL?

You could easily instruct the map to use the string comparison (if/when
needed) instead by providing an extra template argument for the map
declaration.

Of course, one _can_ do that. Often, one even _must_ do that. And sometimes,
people are not aware of the issue (which addresses your claim that it
is "easy": nothing is easy to do when you don't know that you should),
which is why related bugs come up in postings to this group where the
standard answer is: use std::string or provide a forwarding comparison
predicate.

IOW, STL does what it is told to do. It does not attempt to read your
mind. This is a Good Thing IMO.

I did not give an evaluation of any sort. I just felt the need to point out
that there are technical issues when using pointers in STL containers. I
did not suggest changing the STL nor did I claim that other alternatives
are preferable. To me, it's just a matter of awareness.


Best

Kai-Uwe Bux
 
S

Stefan Ram

Chris Thomasson said:
In C, if malloc returns NULL, what do you do?

In C, you usually want to make sure not to dereference
this result and you do not need to call free for it.

For example, assume that a calculation needed a
temporary buffer of 1024 char objects.

This buffer might be obtained from the stack, but just
to show how a 0 result from malloc would be handled,
I request the buffer from the heap.

/** Does some calculation.
@param x the argument for the calculation
@param y where to store the result in case of success
@returns 0 to indicate success, otherwise an error has happened,
and y does not refer to a valid result */
int calculate( double const x, double * const y )
{ char * buffer; if( buffer = malloc( 1024 ))
{ int const status = do_calculate( x, y, buffer );
free( buffer ); return status; }
else return 1; }
 
G

Greg Herlihy

In case of a file you know the file size in advance and know if the
size is within the limits of your function contract.

The program could well determine that the file's size does fall within
the limits of its "contract" - but nonetheless have its attempt to
allocate enough memory to open the file - fail. Moreover, one could
imagine that a reasonable contract for a file-opening routine would be
to open the requested file - but to do so only if enough memory is
available. So not every attempted memory allocation has to succeed -
for a program to operate correctly.
The Java language
distinguishes between (recoverable) Exceptions and (fatal) Errors.
What can you do after OOM? Can you recover vital memory to proceed?

There may be no need for the program to recover any memory. After all,
an out-of-memory error does not necessarily mean that the program is
close to exhausting its available memory. In fact, the app has just as
much free memory available ater the failed allocation as it had
beforehand. The only sure conclusion that one draw from an out-of-
memory is: that the amount of memory requested - was too large.
a fatal error (like stack overflow and
memory corruption) that should lead to more or less abrupt termination
of the program. This also means that you need not write your code as
if std::bad_alloc were a recoverable exception.

Stack overflows and memory corruption represent irretrievable loss of
data - data needed for the program to operate correctly. A memory
allocation failure does not represent a similar loss of data; so there
is no reason why a memory allocation failure should necessarily be a
fatal error. On the contrary, for certain types of programs
(particular those that are document-oriented), a well-written program
will anticipate that certain, discretionary memory allocations will
fail - and will therefore handle that possibility, correctly.

Greg
 
N

Nick Keighley

really? This is kind of scary to learn...


[...] this does not justify the claim posted by Mr.
Bibinger: "Put simply, STL doesn't work with pointers.". For example, in
case of polymorphic objects a vector of raw pointers is a quite
reasonable thing to have, especially if the lifetime of the objects is
maintained elsewhere (by GC, for example).

ah good. I was beginning to worry... A vector of pointers to
polymorphic
objects seems like a *very* resonable thing to have!

<snip>
 
J

James Kanze

On Jun 15, 11:02 am, (e-mail address removed) (Roland Pibinger) wrote:

[...]
Stack overflows and memory corruption represent irretrievable
loss of data - data needed for the program to operate
correctly.

That's true for memory corruption, but not for stack overflow.
Stack growth is memory allocation; the only real difference
between it and operator new failing is that C++ doesn't provide
any formal means of managing it. Under most Unix, or at least,
under Solaris, there are means if you know what you're doing,
and I've written server applications which were guaranteed not
to crash because of stack overflow---they would respond with an
"insufficient resources" error, just as they would if new
failed.

In practice, for some types of servers, crashing because you
couldn't allocate memory is just not allowed. (For a lot of
others, of course, it *is* what you want to do. It all depends
on the application.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top