Destructor query - c++

I have this below program, where I am passing a vector by reference to a function myFunc and inside this function, I am adding few elements to the vector.
I am not freeing object creating with new, for now ignore the memory leak due to this.
After myFunc() execution is complete I am printing the variables ctor and dtor
to know how many times constructor and destructor were called.
Output is:
Before Exiting 5 7
I am creating 5 objects so ctor is 5. But why is dtor 7? From where do the extra two counts? Am I missing something?
#include
#include
using namespace std;
static int ctor = 0;
static int dtor = 0;
class MyClass
{
public:
MyClass(int n)
{
i = n;
ctor++;
// cout << "Myclass ctor " << ctor << endl;
}
~MyClass()
{
dtor++;
// cout << "Myclass dtor" << dtor << endl;
}
private:
int i;
};
void myFunc(vector<MyClass> &m);
void myFunc(vector<MyClass> &m)
{
MyClass *mc;
for(int i = 0; i < 5; i++)
{
mc = new MyClass(i);
m.push_back(*mc);
}
}
int main()
{
vector<MyClass> m;
vector<MyClass>::iterator it;
myFunc(m);
cout << "Before Exiting " << ctor << " " << dtor << endl;
}

Vectors copy around objects, but only your int constructor increments ctor. That's not accounting for copy constructed objects, and because you didn't provide one, the compiler provided it for you.
Add
MyClass(const MyClass& rhs) i(rhs.i) { ++ctor; }
to your class to see if that balances the count.

Vectors start at a low size. When you push an element into them, they make a copy of it using the copy constructor so you don't see your normal constructor get called. When the vector size grows beyond its limit, it will increase its limit by a multiple of its current size (e.g. double it).
Vectors are guaranteed to always keep objects in contiguous memory, so if adding a new object exceeds the vectors capacity() (i.e. size() + 1 > capacity()), the vector allocates new memory somewhere and copies all elements into it. This will again use the copy constructor. So, your elements from the vector pre-resize will call their destructors after they are copied into the newly allocated space with their copy-constructor.
So, more destructor calls than normal constructor calls :)

Vectors sometimes call another constructor, copy constructor, which was implicitly generated by the compiler for your class. That's why some ctor++ calls are missing: not all objects were constructed with the constructor you defined, some were constructed with the other one.
To ensure correct behavior of a type (class) with vector, you must implement copy constructor for it:
MyClass(const MyClass& rhs) { i = rhs.i; ++ctor; } // copy constructor
...because the one generated by compiler does nothing.

As indicated by others, the reason behind your result is the copy constructor and resizing of the vector. A vector has both a size and a capacity. The capacity is normally always doubled when the vector has to resize to accommodate new elements so that resizing does not have to happen all that often.
Adding some trace code to print out the vector capacity between each push_back gives more clarity into this behaviour.
m.capacity(): 0
m.capacity(): 1
m.capacity(): 2
m.capacity(): 4
m.capacity(): 4
m.capacity(): 8
Before Exiting 5 7
What actually happens here is that the only time the destructor is called is when the vector is resized (see why below). The first time it's resized it has no elements, thus the destructor is never called. The second time, the capacity is 1 so the destructor is called once. The third time it's called twice and the fourth time it's called four times. This totals seven times called, just as the counter shows.
The elements dynamically allocated in myFunc are never deallocated, so the destructor never runs there, and the final printout ("Before Exiting...") is done before leaving the scope in which the vector is allocated, so the destructor for the last "vector reincarnation" isn't called until after that printout. Therefore, the destructor of MyClass is only called when the vector is resized.

ยง 12.8.8 of the C++ standard says: If the class definition does not explicitly declare a copy constructor, there is no user-declared move constructor, and there is no user-declared move assignment operator, a copy constructor is implicitly declared as defaulted (8.4.2). Such an implicit declaration is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.
Basically, since your struct violates the rule of five, the compiler made a copy constructor and assignment operator for you. That other constructor doesn't increment ctor, but uses the destructor you defined. The vector is then using that alternate constructor, as a speed improvement.
If you add protected: MyClass(const MyClass& b); to the class declaration, this problem goes away.

Related

Does the move constuctor of std::vector call the move constructor of the items

I wrote the following code to understand the move sementics of std::vector
class PointerHolder
{
public:
PointerHolder()
{
cout << "Constructor called" << endl;
}
//copy constructor
PointerHolder(const PointerHolder& rhs)
{
cout << "Copy Constructor called" << endl;
}
//copy assignment operator
PointerHolder& operator = (const PointerHolder& rhs)
{
cout << "Copy Assignment Operator called" << endl;
return *this;
}
// move constructor
PointerHolder(PointerHolder&& rhs)
{
cout << "Move Constructor called" << endl;
}
// move assignment operator
PointerHolder& operator = (PointerHolder&& rhs)
{
cout << "Move Assignment Operator called" << endl;
return *this;
}
};
void processVector(std::vector<PointerHolder> vec)
{
}
int main()
{
vector<PointerHolder> vec;
PointerHolder p1;
PointerHolder p2;
vec.push_back(p1);
vec.push_back(p2);
cout << "Calling processVector\n\n" << endl;
processVector(std::move(vec));
}
Since I pass an Rvalue reference of the vector When calling processVecor, what Actually should get called is the move constructor of the std::vector when the function parameter object is formed. Is that right ?
So I expected the move constructor of the vecor within itself woud call the move constructor of the PointerHolder class.
But there was no evidence printed to confirm that.
Can you please clarify the behaviour. Doesn't the move constructor of the std::vector in turn call the move constructor of the individual items
No. Note that the complexity requirement of move contructor of std::vector is constant.
Complexity
6) Constant.
That means the move contructor of std::vector won't perform move operation on every individual elements, which will make the complexity to be linear (like copy constructor). The implementation could move the inner storage directly to achieve it.
No. It pilfers the entire block of memory with all the elements instead. Why bother moving the contents when you can just grab the whole thing?
(The allocator-extended move constructor will need to perform a memberwise move if the supplied allocator compares unequal to the source vector's allocator.)
No, it doesn't require the elements to be moved when calling the move constructor of the std::vector. To understand why, I think you should have a good mental model of how std::vector is implemented. (Most implementations look like this, except they need some more complexity for dealing with allocators)
So what is std::vector?
In the simplest form, it has 3 members:
A capacity: (size_t)
A size: (size_t)
A pointer to data (T*, std_unique_ptr, void*)
The size indicates how many elements in use, the capacity indicates how much data fits in the currently allocated data. Only when your new size would become larger than the capacity, the data needs to be reallocated.
The data that is allocated is uninitialized memory, in which in-place the elements get constructed.
So, given this, implementing the move of a vector would be:
Copy over capacity/size
Copy over the pointer and set to nullptr in original (same behavior as unique_ptr)
With this, the new instance is completely valid. The old one is in a valid but unspecified state. This last one means: you can call the destructor without crashing the program.
For vector, you can also call clear to bring it back to a valid state, or the operator=.
Given this model, you can easily explain all operators. Only move-assignment is a bit more complex.
No. It doesn't call the move constructor. To call move constructor of element you will have to call std::move while pushing to vector itself.
int main()
{
vector<PointerHolder> vec;
PointerHolder p1;
PointerHolder p2;
vec.push_back(std::move(p1));
vec.push_back(p2);
cout << "Calling processVector\n\n" << endl;
processVector(std::move(vec));
}
output
Constructor called
Constructor called
Move Constructor called
Copy Constructor called
Calling processVector
If we're looking at the standard (https://en.cppreference.com/w/cpp/container/vector/vector), it says, moving requires constant amount of time O(1).
Regardless of that, if we're looking at most common implementations, std::vector is a dynamic array. A dynamic array first allocates for example space for 8 elements. If we need space for 9 that this 8 is multiplied or increased by a specific amount, often multiplied bei 1.44, 2 or sth. like that.
But as concerns the moving aspect: what are our member variables and how do we move them? Well, the dynamic array is just - as mentioned - a pointer to the first element and if we wanna move the structure we'll copy the pointer to the other object and set the old pointer to nullptr (or NULL if you don't care for the issue for what nullptr has been implemented for, nullptr is obviously preferrable). And of course things like internal saved size (if saved) has to be copied and in the old object has to be set to zero as well (or whatever move semantics are there).

Copy Constructor called multiple times while doing push_back in a vector [duplicate]

I am a bit confused with the way vector push_back behaves, with the following snippet I expected the copy constructor to be invoked only twice, but the output suggest otherwise. Is it a vector internal restructuring that results in this behaviour.
Output:
Inside default
Inside copy with my_int = 0
Inside copy with my_int = 0
Inside copy with my_int = 1
class Myint
{
private:
int my_int;
public:
Myint() : my_int(0)
{
cout << "Inside default " << endl;
}
Myint(const Myint& x) : my_int(x.my_int)
{
cout << "Inside copy with my_int = " << x.my_int << endl;
}
void set(const int &x)
{
my_int = x;
}
}
vector<Myint> myints;
Myint x;
myints.push_back(x);
x.set(1);
myints.push_back(x);
What happens:
x is inserted via push_back. One copy occurs: The newly created element is initialized with the argument. my_int is taken over as zero because xs default constructor initialized it so.
The second element is push_back'd; The vector needs to reallocate the memory since the internal capacity was reached. As no move constructor is implicitly defined for Myint1 the copy constructor is chosen; The first element is copied into the newly allocated memory (its my_int is still zero... so the copy constructor shows my_int as 0 again) and then x is copied to initialize the second element (as with the first in step 1.). This time x has my_int set to one and that's what the output of the copy constructor tells us.
So the total amount of calls is three. This might vary from one implementation to another as the initial capacity might be different. However, two calls are be the minimum.
You can reduce the amount of copies by, in advance, reserving more memory - i.e. higher the vectors capacity so the reallocation becomes unnecessary:
myints.reserve(2); // Now two elements can be inserted without reallocation.
Furthermore you can elide the copies when inserting as follows:
myints.emplace_back(0);
This "emplaces" a new element - emplace_back is a variadic template and can therefore take an arbitrary amount of arguments which it then forwards - without copies or moves - to the elements constructor.
1 Because there is a user-declared copy constructor.
You got it...it was the resizing. But I'll just point out that if you're doing some bean counting on your constructors, you might be interested in "emplacement":
#include <iostream>
#include <vector>
using namespace std;
class Myint
{
private:
int my_int;
public:
explicit Myint(int value = 0) : my_int(value)
{
cout << "Inside default " << endl;
}
Myint(const Myint& x) : my_int(x.my_int)
{
cout << "Inside copy with my_int = " << x.my_int << endl;
}
Myint(const Myint&& x) noexcept : my_int(x.my_int) {
cout << "Inside move with my_int = " << x.my_int << endl;
}
};
int main() {
vector<Myint> myints;
myints.reserve(2);
myints.emplace_back(0);
myints.emplace_back(1);
// your code goes here
return 0;
}
That should give you:
Inside default
Inside default
And, due to the noexcept on the move constructor...if you delete the reserve you'd get a move, not a copy:
Inside default
Inside default
Inside move with my_int = 0
There's no real advantage with this datatype of a move over a copy. But semantically it could be a big difference if your data type was more "heavy weight" and had a way of "moving" its members that was more like transferring ownership of some pointer to a large data structure.
When the size of the vector is increased with the second push_back, the existing contents of the vector must be copied to a new buffer. To verify, output myints.capacity() after the first push_back, it should be 1.
This depends on how much memory was reserved to an object of type std::vector. It seems that when push_back was first executed there was allocated memory only for one element. When the second time push_back was called the memory was reallocated to reserve memory for the second element. In this case the element that is already in the vector is copied in the new place. And then the second element is also added.
You could reserve enough memory yourself that to escape the second call of the copy constructor:
vector<Myint> myints;
myints.reserve( 2 );
You're correct in assuming the additional invocation of the copy constructor comes from internal restructuring of the vector.
See this answer for more detail: https://stackoverflow.com/a/10368636/3708904
Or this answer for the reason why copy construction is necessary: https://stackoverflow.com/a/11166959/3708904

c++ Vector behavior [duplicate]

#include <iostream>
#include <vector>
using namespace std;
class base
{
int x;
public:
base(int k){x =k; }
void display()
{
cout<<x<<endl;
}
base(const base&)
{
cout<<"base copy constructor:"<<endl;
}
};
int main()
{
vector<base> v;
base obase[5]={4,14,19,24,29};
for(int i=0; i<5; i++)
{
v.push_back(obase[i]);
}
}
When data is inserted into vector, copy to that data goes to vector using the copy constructor.
When i run this program,
for the first insertion (i=0), one time copy constructor is called.
for the second insertion (i=1), two times copy constructor is called
for the third insertion (i=3), three times copy constructor is called
for the fourth insertion (i=3), four times copy constructor is called
for the fifth insertion (i=4), five times copy constructor is called
Please any one can tell me why this is happening? For each insertion, shouldn't the copy constructor be called only once?
calls to push_back() increase the size of the vector as necessary, which involves copying of vector's contents. Since you already know that it's going to contain five elements, either v.reserve(5); right before the loop, or use the range constructor:
base obase[5]={4,14,19,24,29};
vector<base> v(obase, obase+5);
Your copy constructor is flawed, you forgot to actually copy the data :)
base(const base& that) : x(that.x)
{
cout << "base copy constructor\n";
}
Also, if you have a modern compiler, you can write a move constructor and learn something new:
base(base&& that) : x(that.x)
{
cout << "base move constructor\n";
}
If v needs to resize its internal buffer, it will usually allocate a totally fresh memory area, so it needs to copy all the objects that were previously in the vector to the new location. This is done using regular copying, so the copy constructor is invoked.
You should call reserve() on the vector to reserve storage upfront if you can estimate how many elements you are going to need.
Note that the resize/growth behaviour of std::vector is implementation-dependent, so your code sample will produce different results with different standard library implementations.

Why emplace_back does matter?

#include <iostream>
#include <vector>
struct T{
T(){
std::cout << "Constructor\n";
}
~T(){
std::cout << "Destructor\n";
}
};
int main() {
std::vector<T> vec;
vec.push_back(T());
vec.push_back(T());
return 0;
}
The output is:
(1)Constructor
(2)Destructor
(3)Constructor
(4)Destructor
(5)Destructor
(6)Destructor
(7)Destructor
Why there is so much desructors calls? I see that:
(1) consruct temporary object temp1
(2) destruct temp1
(3) consruct temporary object temp2
(4) destruct temp2
Then it was called copy constructor or move constructor for temp1 and temp 2. So, (5) and (6) are clear. But what about (7)?
Let's expand your structure a bit:
struct T {
T() {
std::cout << "Constructor\n";
}
T(const T&) {
std::cout << "Copy Constructor\n";
}
T(T&&) {
std::cout << "Move Constructor\n";
}
~T() {
std::cout << "Destructor\n";
}
};
And separate calls to push_back method:
vec.push_back(T()); // 1
std::cout << "--- --- ---\n";
vec.push_back(T()); // 2
std::cout << "--- --- ---\n";
Now the output looks more complete:
Constructor
Move Constructor
Destructor
--- --- ---
Constructor
Move Constructor
Copy Constructor
Destructor
Destructor
--- --- ---
Destructor
Destructor
The first group:
Constructor
Move Constructor
Destructor
corresponds to the first push_back call:
vec.push_back(T()); // 1
The output might be decrypted easily:
Constructor // Create a temporary
Move Constructor // Move a temporary into the internal vector storage
Destructor // Destroy a temporary
The second group:
Constructor
Move Constructor
Copy Constructor
Destructor
Destructor
corresponds to the second push_back call:
vec.push_back(T()); // 2
and a little bit more complicated:
Constructor // create a temporary
Move Constructor // move it into the newly allocated vector storage
Copy Constructor // copy previously created element into the new storage
Destructor // destroy old storage
Destructor // destroy temporary
Here you should remember that vector class allocates its memory internally and then manages it to provide enogh space for all elements. So, if you add more elements, new allocations happen and old elements are copied or moved into the new storage.
In case of known size you might use reserve method, which simply reserves enough memory for a particular number of elements. It allows to avoid unnecessary memory reallocations and copying or moving elements during these reallocations on adding new elements into the vector (at least until you don't exceed the reserved size).
The third group:
Destructor
Destructor
corresponds to the vector vec destructor call at the end of the program.
emplace_back matters for "move only" types (like std::unique_ptr).
This is wrong and an oversimplification. Not all containers are created equally. For your vector example, if we use reserve the implementation can do a move assign rather than a construct, eliding our copy/extraneous destructor:
std::vector<T> v;
v.reserve(2);
v.emplace_back(1);
v.emplace_back(1);
Output:
Constructor
Constructor
---
Destructor
Destructor
For a set:
std::set<T> s;
s.emplace(1);
s.emplace(1);
We get the same output. Why though? A set should theoretically construct only one object since sets are unique right? In actuality, the typical implementation constructs a temporary node in order to perform the comparison, accounting for the extra construct/destruct even though it never enters the container.

how to hold user defined type in STL stack?

My question is: is the following code about STL stack correct?
in the code, complex is a user defined class with constructor and destructor defined.
after place 1, complex constructor and destructor are called 5 times respectively,
and after place 2, complex destructor are called 5 times again due to pop().
so in total destructor are called more than constructor. IMO it should not happen.
Is my code correct? if not correct how to correct it? suppose I still use stack rather than stack
#include <stack>
#include "complex.h"
using namespace std;
void test_stack(){
stack<complex> mystack2;
cout << "Pushing complex..." << endl;
for (int i=0; i<5; ++i) {
complex c(i,i);
mystack2.push(c);
}
//place 1
cout << "Popping out complex..." << endl;
while (!mystack2.empty())
{
cout << " " << mystack2.top();
mystack2.pop(); //void pop();
}
//place 2
cout << endl;
}
To answer your original question, there is nothing wrong with your code. However, your understanding is a little off.
As others have noted, mystack2.push(c) will call the complex's copy constructor. So in total you have 5 calls to the constructor, 5 to the copy constructor, and 10 to the destructor.
This brings up a few important points. As you've noticed, the following code:
for (int i=0; i<5; ++i) {
complex c(i,i);
mystack2.push(c);
}
First creates a complex (c), then a copy is added to the stack, and the original complex is destroyed when c goes out of scope. In C++11, the extra copy is unnecessary, and you can do the following:
for (int i=0; i<5; ++i) {
mystack2.emplace(i, i);
}
Which will let the stack do the construction of the object, eliminating the need for a copy.
Another point which I think led to your confusion that the constructor was called 10 times, is that you said complex only defines a constructor and a destructor. If you don't define a copy constructor (and don't mark it private or deleted), one will be created automatically by the compiler. There's actually a little more to it than it with C++11, and I direct you to this question for details - Conditions for automatic generation of default/copy/move ctor and copy/move assignment operator?. The important thing to note, though, is that in this case your call to push was definitely calling a compiler-generated copy constructor.
You are probably not taking into account the copy constructor which would be called at
mystack2.push(c);
For value-type classes like complex, a copy constructor will be created for you automatically if you don't define your own.
You can create a copy constructor with something like this:
complex( complex const & other )
: real(other.real)
, imag(other.imag)
{
cout<<"complex::copy_constructor called"<<endl;
}
To simplify it, I won't mention that each of these happens 5 times:
complex c(i,i); - constructor called
mystack2.push(c); - constructor called
c falls out of scope - destructor called
mystack2.pop(); - destructor called
Note: To see what's going on add trace messages in the constructor and destructor. Don't forget the rule of three.