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.
It constructs a
Path
copy from the heap-allocated*path
object.It resizes the
paths
vector. This can sometimes involve just increasing an integer, but at other times it involves moving every existingPath
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
C++ Get Description of an Exception Caught in Catch(...) Block
Compiling and Linking Third Party Libraries in VS 2015
Why Does Glgetstring(Gl_Version) Return Null/Zero Instead of the Opengl Version
How to Get Process Handle from Process Id
Specifying Default Parameter When Calling C++ Function
C++ Class or Struct Compatiblity with C Struct
Stl Ordering - Strict Weak Ordering
How Is Tr1::Reference_Wrapper Useful
What Do the C and C++ Standards Say About Bit-Level Integer Representation and Manipulation
How to Handle a Ctrl-Break Signal in a Command Line Interface
Is There a C++ Equivalent to Getcwd
What's the Semantically Accurate Position for the Ampersand in C++ References
Hide a C++ Code Block from Intellisense
Good C++ Solutions to the "Bring All the Zeros to the Back of the Array" Interview Challenge