Pointers, Vectors, and Destructors

Discussion in 'C++' started by joevandyk@gmail.com, Dec 9, 2004.

  1. Guest

    Below, I have a class Container that contains a vector. The vector
    contains pointers to a Base class. When the Container destructor is
    called, I would like to delete all the objects that the pointers in the
    vector are pointing to.

    It works fine, IF I comment out the destructors in Base and Inherited.
    If I leave the explicit destructors in there, it seg faults. Why is
    there a difference?


    Thanks,
    Joe



    #include <iostream>
    #include <vector>

    using namespace std;

    struct Base {
    virtual ~Base() {}
    };

    struct Inherited : public Base {
    ~Inherited() {}
    };

    class Container
    {
    public:
    vector<Base*> v;

    ~Container()
    {
    // Need to delete pointed-to objects in v
    for (vector<Base*>::iterator i = v.begin();
    i != v.end();
    ++i)
    {
    cout << "Deleting " << *i << endl;
    delete *i;
    }
    }
    };

    int main()
    {
    Container c;

    Inherited *f = new Inherited();

    // Adding two pointers to the same object to Container
    c.v.push_back(f);
    c.v.push_back(f);

    return 0;
    }
     
    , Dec 9, 2004
    #1
    1. Advertising

  2. wrote:
    > Below, I have a class Container that contains a vector. The vector
    > contains pointers to a Base class. When the Container destructor is
    > called, I would like to delete all the objects that the pointers in the
    > vector are pointing to.
    >
    > It works fine, IF I comment out the destructors in Base and Inherited.
    > If I leave the explicit destructors in there, it seg faults. Why is
    > there a difference?


    None whatsoever. Your program produces undefined behaviour in both
    cases. See below.

    >
    >
    > Thanks,
    > Joe
    >
    >
    >
    > #include <iostream>
    > #include <vector>
    >
    > using namespace std;
    >
    > struct Base {
    > virtual ~Base() {}
    > };
    >
    > struct Inherited : public Base {
    > ~Inherited() {}
    > };
    >
    > class Container
    > {
    > public:
    > vector<Base*> v;
    >
    > ~Container()
    > {
    > // Need to delete pointed-to objects in v
    > for (vector<Base*>::iterator i = v.begin();
    > i != v.end();
    > ++i)
    > {
    > cout << "Deleting " << *i << endl;
    > delete *i;
    > }
    > }
    > };
    >
    > int main()
    > {
    > Container c;
    >
    > Inherited *f = new Inherited();
    >
    > // Adding two pointers to the same object to Container
    > c.v.push_back(f);
    > c.v.push_back(f);


    How many pointers to the _same_ object does 'c.v' now contain? How
    many times will you attempt to delete that object?

    >
    > return 0;
    > }
    >


    V
     
    Victor Bazarov, Dec 9, 2004
    #2
    1. Advertising

  3. Guest

    Victor Bazarov wrote:
    > wrote:
    > > Below, I have a class Container that contains a vector. The vector
    > > contains pointers to a Base class. When the Container destructor

    is
    > > called, I would like to delete all the objects that the pointers in

    the
    > > vector are pointing to.
    > >
    > > It works fine, IF I comment out the destructors in Base and

    Inherited.
    > > If I leave the explicit destructors in there, it seg faults. Why

    is
    > > there a difference?

    >
    > None whatsoever. Your program produces undefined behaviour in both
    > cases. See below.
    >
    > >
    > >
    > > Thanks,
    > > Joe
    > >
    > >
    > >
    > > #include <iostream>
    > > #include <vector>
    > >
    > > using namespace std;
    > >
    > > struct Base {
    > > virtual ~Base() {}
    > > };
    > >
    > > struct Inherited : public Base {
    > > ~Inherited() {}
    > > };
    > >
    > > class Container
    > > {
    > > public:
    > > vector<Base*> v;
    > >
    > > ~Container()
    > > {
    > > // Need to delete pointed-to objects in v
    > > for (vector<Base*>::iterator i = v.begin();
    > > i != v.end();
    > > ++i)
    > > {
    > > cout << "Deleting " << *i << endl;
    > > delete *i;
    > > }
    > > }
    > > };
    > >
    > > int main()
    > > {
    > > Container c;
    > >
    > > Inherited *f = new Inherited();
    > >
    > > // Adding two pointers to the same object to Container
    > > c.v.push_back(f);
    > > c.v.push_back(f);

    >
    > How many pointers to the _same_ object does 'c.v' now contain? How
    > many times will you attempt to delete that object?
    >


    c.v has two pointers to the same object. I try to delete the object
    twice.

    I agree, bad thing, but was wondering why it seemed to work without
    explicit destructors.

    Is there a way to tell whether or not a pointed-to object has been
    deleted?

    > >
    > > return 0;
    > > }
    > >

    >
    > V
     
    , Dec 10, 2004
    #3
  4. <> wrote...
    > [...]
    > c.v has two pointers to the same object. I try to delete the object
    > twice.
    >
    > I agree, bad thing, but was wondering why it seemed to work without
    > explicit destructors.


    Why anything _seems_? Probably because we have a tendency to believe
    something we really want... Not relevant to C++ of course, but simply
    specific to human psyche.

    > Is there a way to tell whether or not a pointed-to object has been
    > deleted?


    No, there is no generic way. There may be a way on your platform or
    in your RT library, but C++ does not provide any mechanism.

    V
     
    Victor Bazarov, Dec 10, 2004
    #4
  5. Guest

    > Is there a way to tell whether or not a pointed-to object has been
    deleted?

    You could maintain a set of deleted pointers and use this to ensure
    that you don't call delete with the same pointer twice.

    Like this:

    ~Container()
    {
    std::set< Base * > deleted;

    // Need to delete pointed-to objects in v
    for (vector<Base*>::iterator i = v.begin();
    i != v.end();
    ++i)
    {
    if( deleted.find( *i ) == deleted.end() )
    {
    cout << "Deleting " << *i << endl;
    delete *i;

    deleted.insert( *i );
    }

    }
    }
     
    , Dec 10, 2004
    #5
  6. wrote:
    > Below, I have a class Container that contains a vector. The vector
    > contains pointers to a Base class. When the Container destructor is
    > called, I would like to delete all the objects that the pointers in the
    > vector are pointing to.
    >
    > It works fine, IF I comment out the destructors in Base and Inherited.
    > If I leave the explicit destructors in there, it seg faults. Why is
    > there a difference?


    That's undefined behavior, as you are deleting an object twice. What's
    happening then depends on what your implementation does in that case.

    I assume you are asking about this specific behavior and that you know
    you deleted an object more than once.

    It seems that when you don't define a destructor in a class having no
    data member (such as Inherited or Base), *your implementation* generates
    none so no function gets called when an object is destroyed. That's an
    optimization.

    By defining a destructor by hand, you force *your implementation* to
    call your destructor. Therefore, in the first scenario, there are no
    calls to destructors. In the second one, destructors are called.

    If you delete an object twice in the first scenario, no crash occurs
    since you are not using the deallocated memory because you don't call
    destructors. *Your implementation* does not not crash when deallocating
    memory twice.

    If you delete an object twice in the second scenario, a crash occurs
    since you are calling a function (a destructor in that case) on
    deallocated memory.

    Both scenario are invalid from a standard C++ point of view since you
    are deleting an object more than once. This situation is exactly what
    we call "undefine behavior": anything could happen.


    For your specific case, since you have a container of pointers which you
    must delete, I would use a std::set, which allows no duplicates. That
    will prevent such misusage.

    Jonathan
     
    Jonathan Mcdougall, Dec 10, 2004
    #6
  7. You can actually avoid similar problems if you use std::auto_ptr
    whenever the ownership
    of a pointer changes.
    And of course you'll need a copy constructor and assignment operator as
    well
    (or prevent them as shown below).

    #include <memory>
    class Container {
    public:
    // ...
    void push_back(std::auto_ptr<Base*> base) {
    v.push_back(base.release(); }
    private:
    // prevent copying: not implemented:
    Containter(const Container&);
    // prevent assignment: not implemented:
    Container& operator=(const Container&);
    private:
    vector<Base*> v;
    };

    Alternatively boost provides boost::shared_ptr.

    Regards,
    Stephan Brönnimann

    http://www.osb-systems.com
    Open source rating and billing engine for
    communication networks.
     
    =?iso-8859-1?q?Stephan_Br=F6nnimann?=, Dec 10, 2004
    #7
  8. PKH Guest

    <> wrote in message
    news:...
    > Victor Bazarov wrote:
    >> wrote:


    <snip>
    > Is there a way to tell whether or not a pointed-to object has been
    > deleted?
    >


    Do a search on Smartpointers. They are good for this kind of thing, by
    doing reference counting, or by integrating smartpointers with the delete
    operator.

    PKH
     
    PKH, Dec 10, 2004
    #8
  9. Lionel B Guest

    Jonathan Mcdougall wrote:
    > wrote:
    > > Below, I have a class Container that contains a vector.
    > > The vector contains pointers to a Base class. When
    > > the Container destructor is called, I would like to
    > > delete all the objects that the pointers in the vector
    > > are pointing to.


    /.../

    > For your specific case, since you have a container of
    > pointers which you must delete, I would use a std::set,
    > which allows no duplicates. That will prevent such misusage.


    Unless, of course, the OP wants/needs (for whatever reason) to allow
    mutiple pointers to the same object. In which case some kind of
    reference counting (smart pointer?) is probably the way to go.
    --
    Lionel B
     
    Lionel B, Dec 10, 2004
    #9
  10. Duane Guest

    <> wrote in message news:...
    > Below, I have a class Container that contains a vector. The vector
    > contains pointers to a Base class. When the Container destructor is
    > called, I would like to delete all the objects that the pointers in the
    > vector are pointing to.
    >
    > It works fine, IF I comment out the destructors in Base and Inherited.
    > If I leave the explicit destructors in there, it seg faults. Why is
    > there a difference?


    What if you call clear() on the vector after the delete and
    before pushing back more pointers?

    How about one of the boost smart pointers?
     
    Duane, Dec 10, 2004
    #10
  11. Ron Natalie Guest

    wrote:
    >>Is there a way to tell whether or not a pointed-to object has been

    >
    > deleted?
    >
    > You could maintain a set of deleted pointers and use this to ensure
    > that you don't call delete with the same pointer twice.
    >


    That's also undefined behavior. You're not allowed to use the
    value of a deleted pointer.
     
    Ron Natalie, Dec 10, 2004
    #11
    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. Takeshi
    Replies:
    3
    Views:
    554
    Takeshi
    Nov 1, 2004
  2. Lilith
    Replies:
    4
    Views:
    344
    Ferdi Smit
    Feb 20, 2006
  3. Replies:
    3
    Views:
    703
    Shadowman
    Mar 26, 2008
  4. cerr

    pointers, pointers, pointers...

    cerr, Apr 7, 2011, in forum: C Programming
    Replies:
    12
    Views:
    686
  5. Guest
    Replies:
    0
    Views:
    449
    Guest
    Sep 14, 2005
Loading...

Share This Page