Std::Vector Calling Destructor Multiple Times During Push_Back

Vector push_back calls object destructor

When std::vector expands its storage it copies or moves the current objects into the new storage space. The old objects are thrown away, and that inherently involves calling destructors on the old objects.

If destroying old objects isn't desirable, std::deque has more or less the same operations as std::vector, with somewhat more overhead, but without having to reallocate storage.

If memory usage is not an issue, std::list never moves its stored objects, but each element in the list also has a pair of pointers, one pointing to the previous element in the list, and one pointing to the next element.

Destructor called twice

The last object is deconstructed two times.

Once when you explicitly destruct it, and then once again when the function ends and all variables local to the function auto-destruct. This is undefined behavior.

You should almost never call a destructor yourself.

Why does std::vector call the destructor while leaving a different scope?

paths.push_back(*path);

this does a few things.

  1. It constructs a Path copy from the heap-allocated *path object.

  2. It resizes the paths vector. This can sometimes involve just increasing an integer, but at other times it involves moving every existing Path object and destroying the old ones.

In the first point, you have a leak. new allocates objects on the free store, you are always responsible for ensuring they are cleaned up. Copying the object off the free store into a vector does not clean up the object on the free store.

In the second point, vector actually holds actual objects, not references to them. So when you resize the buffer (which push_back can do), you have to move the values of the objects around, then clean up the ones you are discarding.

That cleanup is the destructor you are doing.

You appear to be a C# or Java programmer. In both of those languages, actual values of objects are really hard to create -- they want to hold onto garbage collected references to objects. An array of objects is actually an array of references to objects in those languages. In C++, a vector of objects is a vector actually containing the objects in question.

Your use of new is also a tip. There is no need for new there, nor is there need for a pointer:

std::vector<cuarl_path::Path> RoverPlanner::get_paths(const char *filename) const
{
pugi::xml_document doc;
doc.load_file(filename);
pugi::xml_node root = doc.document_element();

std::vector<cuarl_path::Path> paths;
for (auto&& path_node : root.children()) {
std::vector<cuarl_path::Segment*> segments;
for (auto segment_node : path_node.children())
{
//do stuff to populate the `segments` vector
}

cuarl_path::Path path = cuarl_path::Path(segments);
paths.push_back(std::move(path)); //Path destructor called here
}

return paths;
}

you'll still get path destructors called on the line (in fact, you'll get an extra one), but your code won't leak. Assuming your move constructor is correct (and in fact moves the state of the path properly), everything should work.

Now a more efficient version looks like:

std::vector<cuarl_path::Path> RoverPlanner::get_paths(const char *filename) const
{
pugi::xml_document doc;
doc.load_file(filename);
pugi::xml_node root = doc.document_element();

std::vector<cuarl_path::Path> paths;
auto&& children = root.children();
paths.reserve(children.size());
for (auto path_node : children) {
std::vector<cuarl_path::Segment*> segments;
for (auto segment_node : path_node.children())
{
//do stuff to populate the `segments` vector
}

paths.emplace_back(std::move(segments));
}

return paths;
}

which gets rid of all of the temporary variables you are messing with, and moves resources when they are of no more use.

Assuming efficient move constructors, the big gains here are that we pre-researve the paths vector (saving lg(n) memory allocations) and we move the segments vector into the constructor of a path (if written right, that could avoid a needless copy of the buffer of segment pointers).

This version also has no destructors called on the line in question, but I don't consider that to be particularly important; the cost of a destructor of an empty path should be nearly free, and even plausible to optimize away.

I also possibly avoided a copy of the path_node object, which could be worth avoiding, depending on how it is written.

vector is calling the destructor even at the moment of push back... why

When using std::vector<test>, elements are copied into the vector.

x.push_back(test("prakash",(new testHelper(10))));

You are creating an instance which is copied then immediately destroyed.

Why does my class's destructor get called when I add instances to a vector?

The problem here is that you're violating the Rule of Three. Your class has a destructor so you need a copy-constructor and an assignment operator, too. Alternatively, you could not allow your class to be copied (for example by making T(T const&) and T& operator=(T const&) private, or by deriving from boost::noncopyable), and then resize the vector instead of using push_back.

In the first case, you can just push_back your class as you usually would. In the second, the syntax would be something like

std::vector<TEST> vec(5);
// vec now has five default-constructed elements of type TEST.

Not doing either of these things is a bad idea, as you are very likely to run into double deletion issues at some point -- even if you think you'll never copy or assign a TEST where x != nullptr, it's much safer to explicitly forbid it.

By the way, if you have member pointers that should be deleted when an object goes out of scope, consider using smart pointers like scoped_ptr, unique_ptr and shared_ptr (and maybe auto_ptr if you're unable to use Boost or C++11).

How does destructor gets called when object are created using Vectors

When I push back one time, I get 2 calls to destructor. 2 push backs,
I get 5 calls to destructor. 3 push backs, I get 9 calls to
destructor.

Before C++11, when you push back an object to a std::vector system copy the object to the container. So if you do one push back system created 2 objects, so system has to call 2 times destructor to clean up.

Since C++11, if you define move copy constructor for your calls, std::vector use move semantics in place of copy constructor and move the object to vector instead copy the object. So system will generate only one destructor call.
Following link will give you better idea http://en.cppreference.com/w/cpp/language/rule_of_three



Related Topics



Leave a reply



Submit