Skip to main content
GameDev.net gamedev.net
🔒 Locked

Quick std::vector question

Started by Sir Sapo Dec 26, 2005 at 4:03 PM 5 replies 6.1k views
Original Post
Sir Sapo
Sir Sapo
Hey everyone! Just a quick question. When I clear() or erase() or pop_back() objects in a vector, are the objects automatically deleted and their destructors called? I have a vector of pointers to objects, and objects are removed and added often, I was just wondering if I needed to do something special to prevent a memory leak.
My Current Project Angels 22 (4E5)
SiCrane
SiCrane
The destructor of the object stored in the vector will be called. For normal pointers, the destructor is a no-op. If you have a vector of pointers you need to call the destructor on the object pointed to manually. Alternately you can use a vector of smart pointers like boost::shared_ptr or you can use a container that automatically deletes the pointers like boost::ptr_vector.
RDragon1
RDragon1
The elements of the container are freed. In your case, that means the pointers are freed. The container doesn't call delete on pointers in the container (imagine the mess if you had a pointer in multiple containers).

This is a good place to tell you to learn about smart pointers. They are objects that act like pointers, and logically 'own' the object, and are responsible for cleaning them up automatically. std::auto_ptr's are part of the standard library, but you can't use these in any of the standard containers. For a nice smart pointer (they are reference-counted smart pointers), learn about the boost.shared_ptr library.

Otherwise, whenever you .clear() or erase things from the container, you'll have to remember when/if it's appropriate to delete the object that the pointer points to. Smart pointers make this stuff much more elegant and simple, not to mention make your code much more exception-safe by default.
RDragon1
RDragon1
Lol. Hi again SiCrane ;)
LilBudyWizer
LilBudyWizer
Seperately, when in doubt set break points.
Keys to success: Ability, ambition and opportunity.
Will F
Will F
Definitely use a vector of boost::shared_ptr. There's some info in section 5 of this link: Using Modern C++ to Eliminate Memory Problems.

If you're still not convinced that you should look into boost::shared_ptr look at this (though it's not directly related to your question).

This is my understanding of how things are working - someone please correct me if i'm wrong.

When you're adding things to a std::vector you are making a copy of the object you're adding. If you've got a vector of pointers (std::vector for example) it's not a big deal because you're just making a copy of a pointer. But if you're adding an object, you are making a copy of the object, which means that if the original object goes out of scope it's destructor will be called. If that object allocates memory and later deletes it in the destructor you'll get in trouble if you haven't defined a copy constructor and assignment operator.

Here's some code that will hopefully illustrate the problem:
#include <vector>#include <iostream>class bar{    public:    bar() {std::cout << "bar constructor called" << std::endl;}    ~bar() {std::cout << "bar destructor called" << std::endl;}};class foo{    bar *i;    public:    foo();    ~foo();    void doSomethingWithTheBar();};foo::foo(){    std::cout << "newing a bar" << std::endl;    i = new bar;    std::cout << "bar's address: " << i << std::endl;}foo::~foo(){    std::cout << "deleting a bar at address: " << i << std::endl;    delete i;}void foo::doSomethingWithTheBar(){    std::cout << "Do something with bar at address: " << i << std::endl;}int main(){    std::vector<foo> vec;    {        foo f;        vec.push_back(f);    }    vec[0].doSomethingWithTheBar();    std::cout << "Uh Oh. The memory at that address has been deleted" << std::endl;}


Here's how it output on my machine:
newing a bar
bar constructor called
bar's address: 0x81bf008
deleting a bar at address: 0x81bf008
bar destructor called
Do something with bar at address: 0x81bf008
Uh Oh. The memory at that address has been deleted
deleting a bar at address: 0x81bf008
bar destructor called


Not good. Here's a way to use boost::shared_ptr to get the behavior you were probably looking for (note that we don't need to explicitly call delete as the boost::shared_ptr will do that when there are no more objects using the pointer):
#include <vector>#include <iostream>#include <boost/shared_ptr.hpp>class bar{    public:    bar() {std::cout << "bar constructor called" << std::endl;}    ~bar() {std::cout << "bar destructor called" << std::endl;}};class foo{    boost::shared_ptr<bar> i;    public:    foo();    void doSomethingWithTheBar();};foo::foo() : i(new bar){    std::cout << "newing a bar" << std::endl;    std::cout << "bar's address: " << i << std::endl;}void foo::doSomethingWithTheBar(){    std::cout << "Do something with bar at address: " << i << std::endl;}int main(){    std::vector<foo> vec;    {        foo f;        vec.push_back(f);    }    vec[0].doSomethingWithTheBar();    std::cout << "It's ok this time, as the memory at that address hasn't been deleted" << std::endl;}


Here's how it output on my machine:
bar constructor called
newing a bar
bar's address: 0x890a008
Do something with bar at address: 0x890a008
It's ok this time, as the memory at that address hasn't been deleted
bar destructor called

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.