Given the code
#include <iostream>
#include <vector>
class Entity {
public:
Entity(const int x, const int y) :
x(x), y(y)
{
this->entities.push_back(*this);
}
int x, y;
std::vector<Entity> entities;
};
int main() {
auto p = Entity(10, 20);
std::cout << p.entities.size() << '\n';
std::cout << p.x << ' ' << p.y << "\n\n";
std::cout << p.entities[0].entities.size() << '\n';
std::cout << p.entities[0].x << ' ' << p.entities[0].y << '\n';
return 0;
}
When entities.push_back is called, the Entity should be copied to the vector. When copied all members should have their copy constuctors called in the following order: (x, y, entities). The problem is in the entities constructor, the "std::vector" constructor should call the "Entity" constructor that will call the "std::vector" constructor again, resulting in a infinite loop.
But according to the output:
1
10 20
0
10 20
The "std::vector" copy constructor is not called.
Where is my error? I'm forgetting some implementation detail?
the "std::vector" constructor should call the "Entity" constructor that will call the "std::vector" constructor again, resulting in a infinite loop
Nope.
The std::vector<Entity> copy constructor will call the Entity copy constructor.
The Entity copy constructor copies the member vector as it currently exists (empty). It does not run the code in the two-element Entity constructor that push_back something to the vector.
You're copying yourself in a constructor, which is generally a bad practice since the object is not yet fully constructed. In this case, the vector is still empty when you call push_back.
Related
I know when a constructer is being called, then it gets created in the memory, and when it gets out of the block it gets destroyed unless it's static.
Know I have this code:
#include <iostream>
#include <string>
using namespace std;
class CreateSample
{
private:
int id;
public:
CreateSample(int i)
{
id = i;
cout << "Object " << id << " is created" << endl;
}
~CreateSample()
{
cout << "Object " << id << " is destroyed" << endl;
}
};
void fuct()
{
CreateSample o1(1);
static CreateSample o2(2);
}
CreateSample o3(3);
void fuct2(CreateSample o);
int main()
{
fuct();
static CreateSample o4(4);
CreateSample o5(5);
fuct2(o5);
return 0;
}
void fuct2(CreateSample o)
{
CreateSample o6 = o;
}
and my concern is in object o5, why it's getting called once and gets destroyed 3 times?
When you wrote fuct2(o5); you're calling the function fuct2 and passing the argument by value. This means a copy of the argument will be passed to the function using the implicitly defined copy constructor. Thus you get the 2nd destructor call corresponding this object o.
Moreover, in fuct2 you have CreateSample o6 = o; which will also use the implicitly defined copy constructor to create o6. Thus you will get a third call to the destructor corresponding to this o6.
You can confirm this for yourself by adding a copy ctor as shown below:
class CreateSample
{
//other code here
public:
CreateSample(const CreateSample&obj): id(obj.id)
{
std::cout<<"Copy ctor called"<<std::endl;
}
};
And the output you will get is:
Object 5 is created <------ctor called for o5
Copy ctor called <------copy ctor called for parameter o
Copy ctor called <------copy ctor called for object o6
Object 5 is destroyed <------destructor called for o6
Object 5 is destroyed <------destructor called for o
Object 5 is destroyed <------destructor called for o5
Demo
Though in this particular example you don't strictly require a custom copy constructor or a custom copy assignment operator, they may be needed in other situations. Refer to the rule of three.
CreateSample o5(5); calls the constructor CreateSample(int). fuct2(o5); and CreateSample o6 = o; call the implicitly-defined default copy constructor CreateSample(CreateSample const&). All three of these variables (o6, o, and o5) call the destructor ~CreateSample() when their scope is exited.
The fix is to follow the rule of three and also define a copy constructor and copy-assignment operator:
class CreateSample
{
// ...
CreateSample(CreateSample const& o) {
id = o.id;
cout << "Object " << id << " is copy-constructed" << endl;
}
CreateSample& operator=(CreateSample const& o) {
cout << "Object " << id << " is copy-assigned from " << o.id << endl;
id = o.id;
return *this;
}
}
Demo on Compiler Explorer
I have an issue with emplace and try_emplace as they always use the copy constructors when moving an object in.
#include <iostream>
#include <unordered_map>
#include <map>
using namespace std;
class Too {
public:
Too(int x, int y):x_(x), y_(y) {
cout << "init " << x_ << endl;
}
Too(const Too& too):x_(too.x_+1), y_(too.y_+1) {
cout << "Copy happen: x = " << x_ << endl;
}
~Too() {
cout << "delete too " << x_ << endl;
}
private:
int x_, y_;
};
std::map<int, Too> v;
int main()
{
v.emplace(100, Too{ 100,23 });
v.try_emplace(12, 12, 13);
Too t = Too(10, 11);
v.try_emplace(11, std::move(t));
}
output
init 100
Copy happen: x = 101
delete too 100
init 12
init 10
Copy happen: x = 11
delete too 10
delete too 101
delete too 12
delete too 11
As you can see, only v.try_emplace(12, 12, 13) do not use the copy constructor.
both v.emplace(100, Too{ 100,23 }) and v.try_emplace(11, std::move(t)) invoke the copy constructor.
So how can it be even when I use std::move(t)?
Any suggestion would be highly appreciated.
Thanks,
Since you've provided a copy constructor for your class, the move constructor Too::Too(Too&&) will not be implicitly generated by the compiler.
Moreover, when there is no move constructor available for a class, the copy constructor can be used.
For using the move constructor you have to explicitly provide an appropriate user-defined move constructor Too::Too(Too&&), then you will get the desired result.
You can add the move constructor either by adding Too(Too&&) = default; or writing your own move constructor which will do the initialization in the constructor initializer list.
I am creating a vector with class objects as below.
#include <iostream>
#include <vector>
using namespace std;
class myclass
{
public:
myclass(int a = 0) : x(a)
{
cout << "myclass constructor" << endl;
}
int x;
};
int main()
{
vector<myclass> v(2, 1);
cout << "size : " << v.size() << endl;
cout << v[0].x << endl;
cout << v[1].x << endl;
}
As per my understanding 2 objects will be created with value '1'. But constructor is getting called only once. When I print the values of the objects, both objects are printing x values as '1'. Below is the output.
myclass constructor
size : 2
1
1
I couldn't understand why constructor is not getting called twice.
1) Is copy constructor getting called here?
I tried to write copy constructor in the class as below
myclass(myclass &obj)
{
x = obj.x;
cout << "Copy Constructor" << endl;
}
but it is throwing following errors while compiling.
vector.cpp:15:9: note: no known conversion for argument 1 from ‘const myclass’ to ‘myclass&’
vector.cpp:10:9: note: myclass::myclass(int)
myclass(int a = 0) : x(a)
^
vector.cpp:10:9: note: no known conversion for argument 1 from ‘const myclass’ to ‘int’
2) Is there any rule that we should not define copy constructor if we are going to create vector of objects of that class? What are the rules we should follow if we are creating vector with user defined class objects?
The copy constructor requires a const reference. Use myclass(const myclass &obj) for the copy constructor.
As per my understanding 2 objects will be created with value '1'. But
constructor is getting called only once.
The constructor is called once and then the object is copied a number of times.
Then the picture is clear from the output:
myclass constructor
Copy Constructor
Copy Constructor
size : 2
1
1
Remember that the vector will also resize and have to copy the elements sometimes.
try
myclass(const myclass &obj)
{
x = obj.x;
cout << "Copy Constructor" << endl;
}
As for part 2, general rule apply : create copy constructor where default member-by member copying will fail.
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
When i run the following program in XCode Version 5.1.1,
#include <iostream>
class MyClass
{
public:
MyClass() { std::cout << "MyClass Cons " << this << std::endl;}
~MyClass() { std::cout << "MyClass Dest " << this << std::endl;}
};
void Func(MyClass myClass)
{
}
int main(int argc, const char * argv[])
{
MyClass myClass1;
Func(myClass1);
return 0;
}
The output i get is
MyClass Cons 0x7fff5fbff918
MyClass Dest 0x7fff5fbff910
MyClass Dest 0x7fff5fbff918
Why is the destructor triggering twice and constructor only once?
The object is destroyed once, as you can see from the pointer values. You also see the destruction of another object. This object is a copy of the original.
By passing the object by value, the copy-constructor is invoked. Since this constructor does not print something, you do not see it in your output.
Add it to the class definition:
MyClass(const MyClass & other) { std::cout << "MyClass Copy-Cons " << this << " from " << &other << std::endl;}
And it should appear:
MyClass Cons 0x7fff1beee7ee
MyClass Copy-Cons 0x7fff1beee7ef from 0x7fff1beee7ee
MyClass Dest 0x7fff1beee7ef
MyClass Dest 0x7fff1beee7ee
The copy is created when you enter Func(). The copy is destroyed when it goes out of scope. This happens when you exit Func(). Finally, the original is destroyed when you exit the main() function.
The reason that you are seeing two destructor is because you are pass the arguments by value. Passing by value calls the copy constructor..
First Destructor:
At the end of the func function, the object goes out of scope, hence, it is destructed.
Second Destructor:
When the program end, the object is destructed.
My suggestion to remove the first destructor is to pass the object by reference rather than by value.
For example,
void Func(MyClass &myClass)
{
}
So now the output will have only:
MyClass Cons 0x7fff5fbff918
MyClass Dest 0x7fff5fbff918
Here the object is constructed twice(as everyone mentioned above). Hence 2 constructor + 2 destructor are called. The reason you are seeing 1 constructor is because you have NOT defined the Copy Constructor. CC is called when a copy is made for the pass-by-value operation.
add the copy constructor and then you can see both the constructor called.
Add Copy constructor - MyClass(const MyClass& obj) { std::cout << "MyClass Copy Cons " << this << std::endl;}