Adding pointer to container

Discussion in 'C++' started by tech, Jun 11, 2008.

  1. tech

    tech Guest

    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());
    }
     
    tech, Jun 11, 2008
    #1
    1. Advertising

  2. tech

    Ian Collins Guest

    tech wrote:
    > 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.

    --
    Ian Collins.
     
    Ian Collins, Jun 11, 2008
    #2
    1. Advertising

  3. tech

    tech Guest

    On Jun 11, 12:15 pm, "Chris Thomasson" <> wrote:
    > "tech" <> wrote in message
    >
    > news:...
    >
    >
    >
    >
    >
    > > 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());
    > > }

    >
    > 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
     
    tech, Jun 11, 2008
    #3
  4. tech

    Daniel Pitts Guest

    Alf P. Steinbach wrote:
    > * Paavo Helde:
    >>
    >> What about:
    >>
    >> void function()
    >> {
    >> m_elements.push_back(NULL);
    >> element*& ref = m_elements.back();
    >> ref = new DerivedElement;
    >> }

    >
    > 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;
    }
    }
    --
    Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
     
    Daniel Pitts, Jun 14, 2008
    #4
  5. On Wed, 11 Jun 2008 03:36:07 -0700 (PDT), tech rote:
    >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());



    --
    Roland Pibinger
    "The best software is simple, elegant, and full of drama" - Grady Booch
     
    Roland Pibinger, Jun 15, 2008
    #5
  6. On Sun, 15 Jun 2008 16:30:19 +0200, "Alf P. Steinbach" wrote:
    >* Roland Pibinger:
    >> 2. You cannot practically 'handle' Out-Of-Memory (OOM).

    >
    >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.


    --
    Roland Pibinger
    "The best software is simple, elegant, and full of drama" - Grady Booch
     
    Roland Pibinger, Jun 15, 2008
    #6
  7. tech

    Daniel Pitts Guest

    Roland Pibinger wrote:
    > On Sun, 15 Jun 2008 16:30:19 +0200, "Alf P. Steinbach" wrote:
    >> * Roland Pibinger:
    >>> 2. You cannot practically 'handle' Out-Of-Memory (OOM).

    >> 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.
    >
    >

    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.

    --
    Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
     
    Daniel Pitts, Jun 15, 2008
    #7
  8. tech

    Kai-Uwe Bux Guest

    Paavo Helde wrote:

    > (Roland Pibinger) kirjutas:
    >
    >> On Wed, 11 Jun 2008 03:36:07 -0700 (PDT), tech rote:
    >>>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.

    >
    > 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
     
    Kai-Uwe Bux, Jun 15, 2008
    #8
  9. tech

    Kai-Uwe Bux Guest

    Paavo Helde wrote:

    > Kai-Uwe Bux <> kirjutas:
    >
    >> Paavo Helde wrote:
    >>
    >>> (Roland Pibinger) kirjutas:
    >>>
    >>>> On Wed, 11 Jun 2008 03:36:07 -0700 (PDT), tech rote:
    >>>>>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.
    >>>
    >>> 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.

    >
    > 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
     
    Kai-Uwe Bux, Jun 15, 2008
    #9
  10. tech

    Stefan Ram Guest

    "Chris Thomasson" <> writes:
    >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; }
     
    Stefan Ram, Jun 16, 2008
    #10
  11. On Sun, 15 Jun 2008 17:31:38 -0700, "Chris Thomasson" wrote:
    >In C, if malloc returns NULL, what do you do? Well, you could try something
    >like:
    >
    >http://groups.google.com/group/comp.lang.c/msg/7b7956d31e6ca5cc


    I agree with you: "we are screwed!!! :^o".



    --
    Roland Pibinger
    "The best software is simple, elegant, and full of drama" - Grady Booch
     
    Roland Pibinger, Jun 16, 2008
    #11
  12. tech

    Greg Herlihy Guest

    On Jun 15, 11:02 am, (Roland Pibinger) wrote:
    > On Sun, 15 Jun 2008 16:30:19 +0200, "Alf P. Steinbach" wrote:
    >
    > >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 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
     
    Greg Herlihy, Jun 16, 2008
    #12
  13. On 16 Jun, 09:28, Paavo Helde <> wrote:
    > Kai-Uwe Bux <> kirjutas:
    > > Paavo Helde wrote:
    > >> Kai-Uwe Bux <> kirjutas:
    > >>> Paavo Helde wrote:
    > >>>> (Roland Pibinger) kirjutas:
    > >>>>> On Wed, 11 Jun 2008 03:36:07 -0700 (PDT), tech rote:


    > >>>>> 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.


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


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


    <snip>

    > [...] 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>


    --
    Nick Keighley
     
    Nick Keighley, Jun 16, 2008
    #13
  14. tech

    James Kanze Guest

    On Jun 16, 2:45 pm, Greg Herlihy <> wrote:
    > On Jun 15, 11:02 am, (Roland Pibinger) wrote:


    [...]
    > > 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.


    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.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Jun 16, 2008
    #14
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Vivi Orunitia
    Replies:
    11
    Views:
    4,530
    Martijn Lievaart
    Feb 4, 2004
  2. Maitre Bart
    Replies:
    2
    Views:
    539
    Maitre Bart
    Feb 11, 2004
  3. Steven T. Hatton
    Replies:
    4
    Views:
    3,959
    Rob Williscroft
    Dec 5, 2004
  4. Replies:
    4
    Views:
    826
    Daniel T.
    Feb 16, 2006
  5. wolverine
    Replies:
    2
    Views:
    469
    Marcus Kwok
    Jul 24, 2006
Loading...

Share This Page