I am reading up on copy constructors and the way they typically receive the parameters as constant references.
Why should the copy constructor accept its parameter by reference in C++?
I wrote a code snippet to test that when a parameter is received by value, whether a copy is created( as stated in the accepted answer of the provided link).
But I don't see the constructor called when an object is received by value.
Please explain why? And isn't a copy created when an object is returned by value too? again no constructor called there as well. Why?
class Vector
{
public:
Vector(){cout << "Vector constructor"<<endl;}
~Vector(){cout << "Vector destructor"<<endl;}
};
Vector use(Vector z)
{
cout << "At call" << endl;
Vector v;
cout << "after definition" << endl;
return v;
}
int main()
{
Vector t;
cout << "After irrelevant" << endl;
use(t);
cout << "After use"<< endl;
}
The output looks as follows:
Vector constructor
After irrelevant
At call
Vector constructor
after definition
Vector destructor
Vector destructor
After use
Vector destructor
Update1: I had missed adding the copy constructor in the initial example. Once that is done the code behaves as expected.
The default constructor is not called when an object is passed by value, the copy (or move) constructor is.
If we trace the copy constructor like this:
class Vector
{
public:
Vector(){cout << "Vector constructor"<<endl;}
Vector(const Vector&) {cout << "Vector copy constructor"<<endl;}
~Vector(){cout << "Vector destructor"<<endl;}
};
Then we see the constructor being called:
Vector constructor
After irrelevant
Vector copy constructor //here
At call
Vector constructor
after definition
Vector destructor
Vector destructor
After use
Vector destructor
There is no copy on the return because the copy is elided by the compiler for efficiency. If you pass -fno-elide-constructors or equivalent to your compiler then you'll see an additional copy.
Copy is created to pass the value, so copy constructor is called there.
#include <iostream>
using std::cout;
using std::endl;
class Vector
{
public:
Vector(){cout << "Vector constructor"<<endl;}
Vector(const Vector&){cout << "Vector copy constructor"<<endl;} // add this line
~Vector(){cout << "Vector destructor"<<endl;}
};
Vector use(Vector z)
{
cout << "At call" << endl;
Vector v;
cout << "after definition" << endl;
return v;
}
int main()
{
Vector t;
cout << "After irrelevant" << endl;
use(t);
cout << "After use"<< endl;
}
output:
Vector constructor
After irrelevant
Vector copy constructor
At call
Vector constructor
after definition
Vector destructor
Vector destructor
After use
Vector destructor
Related
I studied to understand the concept of Move, and I wrote code to see the copy constructor invocation differences.
But it's embarrassing that the copy constructor's call is erratic.
I can't understand why it was printed like this.
Below is a simple example code.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class A {
private:
string s;
public:
A(string s) : s(s) {}
A(const A& ref) {
s = ref.s;
cout << s << " copy constructor" << endl;
}
friend ostream& operator<<(ostream&, const A&);
};
ostream& operator<<(ostream& os, const A& pos) {
os << pos.s << endl;
return os;
}
int main(void) {
vector<A> v;
v.push_back(A("a"));
v.push_back(A("b"));
v.shrink_to_fit();
cout << &v[0] << " v.capacity() : " << v.capacity() << endl;
v.push_back(A("c"));
v.push_back(A("d"));
cout << &v[0] << " v.capacity() : " << v.capacity() << endl;
cout << v[0] << v[1] << v[2] << v[3] << endl;
cout << "///////////////////////////////////" << endl;
vector<A> v2;
v2.emplace_back(("a"));
v2.emplace_back(("b"));
v2.shrink_to_fit();
cout << &v2[0] << " v.capacity() : " << v2.capacity() << endl;
v2.emplace_back(("c"));
v2.emplace_back(("d"));
cout << &v2[0] << " v.capacity() : " << v2.capacity() << endl;
cout << v2[0] << v2[1] << v2[2] << v2[3] << endl;
return 0;
}
output :
a copy constructor
b copy constructor
a copy constructor
0073A578 v.capacity() : 2
c copy constructor
a copy constructor
b copy constructor
d copy constructor
a copy constructor
b copy constructor
c copy constructor
0073EFF0 v.capacity() : 4
a
b
c
d
///////////////////////////////////
a copy constructor
0073A578 v.capacity() : 2
a copy constructor
b copy constructor
a copy constructor
b copy constructor
c copy constructor
0073E970 v.capacity() : 4
a
b
c
d
I don't know why the copy constructor call is erratic.
so.
v.push_back(A("a"));
v.push_back(A("b"));
v.shrink_to_fit();
cout << &v[0] << " v.capacity() : " << v.capacity() << endl;
My expected output for this part is:
a copy constructor
b copy constructor
009A6CA8 v.capacity() : 2
But the output is different.
a copy constructor
b copy constructor
a copy constructor
009A6CA8 v.capacity() : 2
I don't know why I called 'a' one more time in this part.
The same is true for others. Some are duplicated and some are not.
I want to see the difference between a copy constructor and a move call. Is the code wrong?
In the output
a copy constructor
b copy constructor
a copy constructor
009A6CA8 v.capacity() : 2
the first a copy constructor comes from when A(a) is copied into the vector.
The second a copy constructor is because of the vector resizing. When you push the second element, the vector will be resized which could include allocating new memory and copying the old elements into the new memory.
Try printing the capacity before the first push_back and between the first and second push_back (without any shrink_to_fit). You will see the capacity go from 0 to 1 to 2. Each increase in capacity is a new allocation and which will copy all existing elements (but from 0 to 1 there's no elements in the vector, so nothing is copied).
If you want to study the move constructor, you have to provide one. A class with a user-provide copy-constructor (like yours) does not have a move constructor, and therefore will not be moved. Hence, it will be copied in places where it otherwise could be moved.
I always thought std::initializer_list is a lightweight proxy object which would only take const references from list items, instead of copy them.
But then I discovered that copy is actually performed in this case:
struct Test {
Test() {
std::cout << this << " default ctor" << std::endl;
}
Test(const Test&) {
std::cout << this << " copy ctor" << std::endl;
}
~Test() {
std::cout << this << " destructor" << std::endl;
}
};
int main() {
Test a;
Test b;
Test c;
std::cout << "for begin" << std::endl;
for(const auto& current : {a, b, c}) {
std::cout << "Current: " << ¤t << std::endl;
}
std::cout << "for end" << std::endl;
}
Output of above code:
0x63e5acda default ctor
0x63e5acdb default ctor
0x63e5acdc default ctor
for begin
0x63e5acdd copy ctor
0x63e5acde copy ctor
0x63e5acdf copy ctor
Current: 0x63e5acdd
Current: 0x63e5acde
Current: 0x63e5acdf
0x63e5acdf destructor
0x63e5acde destructor
0x63e5acdd destructor
for end
0x63e5acdc destructor
0x63e5acdb destructor
0x63e5acda destructor
Why would std::initializer_list copy items in this case, instead of just taking their references? Is there any "elegant" way to write things similar to for(auto&& x : {a, b, c}), but without copying existing items?
From the documentation on std::initializer_list:
The underlying array is a temporary array of type const T[N], in which each element is copy-initialized (except that narrowing conversions are invalid) from the corresponding element of the original initializer list. The lifetime of the underlying array is the same as any other temporary object, except that initializing an initializer_list object from the array extends the lifetime of the array exactly like binding a reference to a temporary (with the same exceptions, such as for initializing a non-static class member). The underlying array may be allocated in read-only memory.
#include <iostream>
#include <vector>
class A
{
public:
A() { std::cout << "constructor" << std::endl; }
~A() { std::cout << "destructor" << std::endl; }
};
int main()
{
std::vector<A> myvec;
myvec.push_back(A());
myvec.push_back(A());
myvec.clear();
return 0;
}
output:
constructor
destructor
constructor
destructor
destructor
destructor
destructor
There are five calls to the destructor here. The first two are due to the temporaries which are passed to push_back. There are three other calls, but I expected one two extra calls.
myvec.clear() will clear only two contents so destructor of A should call only two times (instead of three). why there is one extra time destructor is called?
But, if I push_back only one element to the vector, instead of two, the output is as I expected.
The call to std::vector::clear isn't really important in this context because, when myvec goes out of scope, its contents will be destroyed anyway.
Let's consider
class A
{
public:
A() { std::cout << "constructor" << std::endl; }
~A() { std::cout << "destructor" << std::endl; }
A (const A &) { std::cout << "A(A&)\n"; }
};
int main()
{
std::vector<A> myvec;
std::cout << "First\n";
myvec.push_back(A());
std::cout << "Second\n";
myvec.push_back(A());
std::cout << '\n'; // to separate the final destruction
myvec.clear();
}
which outputs
First
constructor <-- First A _temporary_ object created when pushing_back
A(A&) <-- vector makes a *copy* of the temporary
destructor <-- Temporary A is destroyed
Second
constructor <-- Second A _temporary_ object created when pushing_back
A(A&) <-- Reallocation happens: vector can't copy because it ran out of space
A(A&) <-- Copy of the second temporary
destructor <-- Destroy of the temporary
destructor <-- Destroy of the first element
destructor
destructor
If you std::vector::reserve some space, you can get rid of the copies made by the reallocation
std::vector<A> myvec;
myvec.reserve(8);
which confirms what said
First
constructor
A(A&)
destructor
Second
constructor
A(A&)
destructor
push_back is still making copies of the parameter: this can be further optimized by making your class moveable.
A(A&&) noexcept = default;
A& operator=(A&&) noexcept = default;
First
constructor
destructor
Second
constructor
destructor
This is most likely due to the reallocation that takes place between the first and the second push_back. If you reserve some space ahead of time, then the deallocations are going to be 2 after the two push_backs, as you have expected.
Try this slightly modified version of your program. There is now a copy constructor and an optional reserve (see comment in the program). It will be a lot clearer what is going on.
#include <iostream>
#include <vector>
using namespace std;
class A
{
public:
A() { cout << " constructor" << endl; }
A(const A & a) { cout << " copy constructor" << endl; }
~A() { cout << " destructor" << endl; }
};
int main()
{
vector<A> myvec;
// myvec.reserve(100); // <<< remove comment to see the difference
cout << "pushback 1" << endl;
myvec.push_back(A());
cout << "pushback 2" << endl;
myvec.push_back(A());
cout << "pushback 3" << endl;
myvec.push_back(A());
cout << "clear" << endl;
myvec.clear();
cout << "end clear" << endl;
return 0;
}
This question already has answers here:
Why is the destructor of the class called twice?
(5 answers)
Closed 9 years ago.
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A's constructor" << endl; }
~A() { cout << "A's destructor" << endl; }
};
class B
{
public:
operator A() const { return A(); }
};
void f(A q) {}
int main()
{
B d1;
f(d1);
return 0;
}
Here's what I expected the code to do before I ran it:
The call to f results in a call to the converter function in class B which returns a temporary object. q's constructor gets called and when f exits, q's destructor gets called. I expected the following output:
A's constructor
A's destructor
but the output I got was:
A's constructor
A's destructor
A's destructor
Since there's another destructor, an extra object must have been created somewhere. Can someone explain what's happening here?
Use this as your class A:
class A
{
public:
A() { cout << "A's constructor: " << this << endl; }
A(const A& a) { cout << "A's copy constructor: " <<this << " form " << &a << endl; }
A(A&& a) { cout << "A's move constructor: " <<this << " form " << &a << endl; }
A& operator=(const A& a) { cout << "A's assignment" <<this << " form " << &a << endl; }
~A() { cout << "A's destructor: "<< this << endl; }
};
And you'll see why.
The question has been asked many times before, but since it is so generic it is difficult to find the older posts.
You are passing your objects around by value, meaning that the copies are created by copy constructor. Copy constructor is what created that "extra object" in your case. Meanwhile, you do not output anything from the copy constructor and therefore don't see the calls.
You have to add a debug output to your copy-constructor as well. That way you will see what is actually constructed and when.
There's potential for there to be 3 A objects constructed here. First is the temporary object created by A() in the conversion operator. Then, since the return type of the conversion operator is A, that temporary is copied into the return value. Then the return value of the conversion is copied into the parameter q of f.
To copy an object, the copy constructor is invoked. The default constructor will not be invoked, so you won't see the "A's constructor" message being printed.
It just so happens that the compiler elides one of these copies so that you only actually have one copy occur. Which one is being elided, I can't tell you (but it's probably the copy into the return value).
I think first destructor call for temporary object and second destructor for object which is constructed by move semantic.
I was going through Josuttis's "Using Map's as associative arrays" (from The C++ Standard Library - A Tutorial and Reference, 2nd Edition) and came across Using a std::map as an associative array on Stack Overflow. Now I have more questions on the constructors that are called when inserting into a map.
Here is my sample program (not using best coding practices; please excuse me for that):
class C
{
public:
string s;
C() { cout << "default " << endl;}
C(const string& p) : s(p)
{ cout << "one param" << endl;}
C(const C& obj)
{
if (this != &obj)
{
s = obj.s;
}
cout << "copy constr" << endl;
}
C& operator = (const C& obj)
{
if (this != &obj)
{
s = obj.s;
}
cout << "copy initializer" << endl;
return *this;
}
};
int main()
{
map<int,C> map1;
C obj("test");
cout << "Inserting using index" << endl;
map1[1] = obj;
cout << "Inserting using insert / pair" << endl;
map1.insert(make_pair(2,obj));
}
The output for this program is:
one param
Inserting using index
default
copy constr
copy constr
copy initializer
Inserting using insert / pair
copy constr
copy constr
copy constr
copy constr
I was assuming that initializing the map by index should call the default constructor and followed by the assignment operator.
But executing map1[1] = obj creates following output;
Inserting using index
default
copy constr
copy constr
copy initializer
Can someone help me to understand the initialization better?
If you read the specification for std::map, it says that operator[] is equivalent to (in this case)
(*((this->insert(make_pair(1,C()))).first)).second
So this explains all the constructor calls you see. First it calls the default constructor C(). Then it calls make_pair, which copies the C object. Then it calls insert, which makes a copy of the pair object you just made, calling the C copy constructor again. Finally it calls the assignment operator to set the inserted object to the one you are assigning it to.
Don;t know.
But this is interesting:
#include <string>
#include <map>
#include <iostream>
using namespace std;
class C
{
public:
string s;
C()
{
cout << "default " << endl;
}
C(const string& p)
: s(p)
{
cout << "one param(" << s << ")" << endl;
}
C(const C& obj)
:s(obj.s)
{
cout << "copy constr(" << s << ")" <<endl;
}
C& operator = (const C& obj)
{
cout << "copy initializer\t" <<;
C copy(obj);
std::swap(s,copy.s);
return *this;
}
};
int main()
{
map<int,C> map1;
cout << "Inserting using index" << endl;
map1[1] = C("Plop");
}
It looks like the default one is created and copied around.
Then the external one is just assinged over it once it has been put in place.
Inserting using index
default
copy constr()
copy constr()
one param(Plop)
copy initializer copy constr(Plop)
What happens if you simply execute map[1];? This may involve internal copies, depending on the implementation of map your standard library uses.
Actually map1[1] = obj will create pair first