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.
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
given the following code:
#include <iostream>
using namespace std;
class A {
public:
A() {
}
A(const A& a) {
cout << "A copy ctor" << endl;
}
virtual ~A() {
cout << "A dtor" << endl;
}
virtual void type() const {
cout << "This is A" << endl;
}
};
class B: public A {
public:
virtual ~B() {
cout << "B dtor" << endl;
}
virtual void type() const {
cout << "This is B" << endl;
}
};
A f(A a) {
a.type();
return a;
}
const A& g(const A& a) {
a.type();
return a;
}
int main() {
A *pa = new B();
cout << "applying function f:" << endl;
f(*pa).type();
cout << "~~~ delete: ~~~" << endl;
delete pa;
return 0;
}
I get the following output:
applying function f:
A copy ctor
This is A
A copy ctor
This is A
A dtor
A dtor
~~~ delete: ~~~
B dtor
A dtor
But I don't understand something. It's seen that while we exists from f the object there is not destructed. Why it's not destructed? (After all, we get out of the scope of the function, so it has to be destroyed, no?)
Note: I emphasized the problematic lines (which I do not understand why it happens in this order)
We going to the function f, at this point, we call to the copy c'tor and printed "A copy ctor" (Ok) , after it, we returns to the function f and going to type() , and then, it's prints "This is A" , now we escpaes from the function f so we calls to the copy c'tor , hence will be printed "A copy ctor" , But, now, what the destructor is not called (while we escape from the function f)..?
I thought that the output will be the following (according to the description above) :
applying function f:
A copy ctor
This is A
A copy ctor (escape from type)
A dtor (escape from type)
This is A (at the main)
~~~ delete: ~~~
B dtor
A dtor
The C++ standard permits by-value function arguments to be destroyed either within the scope of the function, or in the calling scope.
If in the calling scope, it is destroyed at the end of the full expression (usually the ;). If within the function, it is destroyed after the return value is constructed and automatic storage locals are destroyed.
A *pa = new B();
A B is created, with an A subobject base.
cout << "applying function f:" << endl;
f(*pa)//.type();
A sliced copy of *pa is created as the argument to f. Output is A copy ctor\n.
A f(A a) {
a.type();
return a;
}
A .type. is invoked on an instance of A. Note that this A is a copy of *pa, but it is a copy of only the A portion of *pa.
Output is This is A, followed by A(A&&) move ctor, followed optionally by A dtor. In your case you have a copy ctor and not a move ctor, so it is called. This copy/move cannot be elided, as you aren't allowed to elide from function arguments. Output is A copy ctor.
At this point, the compiler may optionally destory the A that is an argument to f. Your compiler does not destroy the argumen to f here.
f(*pa).type();
The temporary A returned by f now has .type() invoked on it. There is no polymorphism here; the method A::type() is called directly. Output is This is A.
Then we reach tne end of the full expression.
Now the temporary returned by f is destroyed, followed by the argument of f if it wasn't destroyed earlier. So output is A dtor.
cout << "~~~ delete: ~~~" << endl;
delete pa;
The B object *pa is destroyed, and then the memory is recycled. As ~A is virtual the proper destructor is called on *pa.
Output is B dtor\nA dtor\n.
The behavior of when the destruction of function parameters occur is implementation defined:
[expr.call]/4
It is implementation-defined whether the lifetime of a parameter ends when the function in which it is defined returns or at the end of the enclosing full-expression.
In your specific case, the implementation chooses the later.
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;}
I run this code for experimenting copy constructor and assignment operator
class AClass {
private:
int a;
public:
AClass (int a_) : a(a_) {
cout << " constructor AClass(int) " << a << endl;
}
AClass(const AClass & x) : a(x.a) {
cout << " copy constructor AClass(const AClass &) " << a << endl;
}
AClass & operator=(const AClass & x) {
a = x.a;
cout << " AClass& operator=(const AClass &) " << a - endl;
return *this;
}
};
AClass g () {
AClass x(8);
return x;
}
int main () {
cout << " before AClass b = g() " << endl;
AClass b = g();
cout << " after" << endl;
cout << " before AClass c(g()) " << endl;
AClass c (g());
cout << " after" << endl;
}
and found that no message appears for the return x;
Why?
Should not the copy constructor or operator= be called?
This is the output:
before AClass b = g()
constructor AClass(int) 8
after
before AClass c(g())
constructor AClass(int) 8
after
The compiler is allowed to elide copying in a case like this. This is called Return Value Optimization.
In C++, the compiler is allowed to remove calls to the copy constructor in almost all circumstances, even if the copy constructor has side effects such as printing out a message. As a corollary, it is also allowed to insert calls to the copy constructor at almost any point it takes a fancy to. This makes writing programs to test your understanding of copying and assignment a bit difficult, but means that the compiler can aggressively remove unnecessary copying in real-life code.
This is known as "return value optimisation". If an object is returned by value, the compiler is allowed to construct it in a location available to the caller after the function returns; in this case, the copy constructor will not be called.
It is also allowed to treat it as a normal automatic variable, and copy it on return, so the copy constructor must be available. Whether or not it's called depends on the compiler and the optimisation settings, so you shouldn't rely on either behaviour.
This is called Copy Ellision. The compiler is allowed to ellide copies in virtually any situation. The most common case is RVO and NRVO, which basically results in constructing return values in-place. I'll demonstrate the transformation.
void g (char* memory) {
new (memory) AClass(8);
}
int main () {
char __hidden__variable[sizeof(AClass)];
g(__hidden__variable);
AClass& b = *(AClass*)&__hidden__variable[0];
cout -- " after" -- endl;
// The same process occurs for c.
}
The code has the same effect, but now only one instance of AClass exists.
The compiler may have optimized away the copy constructor call. Basically, it moves the object.
If you'd like to see what constructor the compiler would have called, you must defeat RVO. Replace your g() function thus:
int i;
AClass g () {
if(i) {
AClass x(8);
return x;
} else {
AClass x(9);
return x;
}
}
I wrote a small test program with a sample class containing also self-defined constructor, destructor, copy constructor and assignment operator. I was surprised when I realized that the copy constructor was not called at all, even though I implemented functions with return values of my class and lines like Object o1; Object o2(o1);
innerclass.hpp:
#include <iostream>
class OuterClass
{
public:
OuterClass()
{
std::cout << "OuterClass Constructor" << std::endl;
}
~OuterClass()
{
std::cout << "OuterClass Destructor" << std::endl;
}
OuterClass(const OuterClass & rhs)
{
std::cout << "OuterClass Copy" << std::endl;
}
OuterClass & operator=(const OuterClass & rhs)
{
std::cout << "OuterClass Assignment" << std::endl;
}
class InnerClass
{
public:
InnerClass() : m_int(0)
{
std::cout << "InnerClass Constructor" << std::endl;
}
InnerClass(const InnerClass & rhs) : m_int(rhs.m_int)
{
std::cout << "InnerClass Copy" << std::endl;
}
InnerClass & operator=(const InnerClass & rhs)
{
std::cout << "InnerClass Assignment" << std::endl;
m_int = rhs.m_int;
return *this;
}
~InnerClass()
{
std::cout << "InnerClass Destructor" << std::endl;
}
void sayHello()
{
std::cout << "Hello!" << std::endl;
}
private:
int m_int;
};
InnerClass innerClass()
{
InnerClass ic;
std::cout << "innerClass() method" << std::endl;
return ic;
}
};
innerclass.cpp:
#include "innerclass.hpp"
int main(void)
{
std::cout << std::endl << "1st try:" << std::endl;
OuterClass oc;
OuterClass oc2(oc);
oc.innerClass().sayHello();
std::cout << std::endl << "2nd try:" << std::endl;
OuterClass::InnerClass ic(oc.innerClass());
ic = oc.innerClass();
}
Output:
1st try:
OuterClass Constructor
OuterClass Copy
InnerClass Constructor
innerClass() method
Hello!
InnerClass Destructor
2nd try:
InnerClass Constructor
innerClass() method
InnerClass Constructor
innerClass() method
InnerClass Assignment
InnerClass Destructor
InnerClass Destructor
OuterClass Destructor
OuterClass Destructor
After some research I read that there is no guarantee that the compiler will use the explicitely defined copy constructor. I do not understand this behavior. Why does the copy constructor even exist then, if we do not know that it is called? How does the compiler decide if it uses it?
Or, even better, is there a way to force the compiler to use the self-defined copy constructor?
Just for completeness with the other answers, the standard allows the compiler to omit the copy constructor in certain situations (what other answers refer to as "Return Value Optimization" or "Named Return Value Optimization" - RVO/NRVO):
12.8 Copying class objects, paragraph 15 (C++98)
Whenever a temporary class object is copied using a copy constructor, and this object and the copy have the same cv-unqualified type, an implementation is permitted to treat the original and the copy as two different ways of referring to the same object and not perform a copy at all, even if the class copy constructor or destructor have side effects. For a function with a class return type, if the expression in the return statement is the name of a local object, and the cv-unqualified type of the local object is the same as the function return type, an implementation is permitted to omit creating the temporary object to hold the function return value, even if the class copy constructor or destructor has side effects. In these cases, the object is destroyed at the later of times when the original and the copy would have been destroyed without the optimization.
So in your innerClass() method, the copy constructor you might think would be called at the return is permitted to be optimized away:
InnerClass innerClass() {
InnerClass ic;
std::cout << "innerClass() method" << std::endl;
return ic; // this might not call copy ctor
}
I agree with Neil, you should not write a class which depends on the copy constructor being called. Namely because the compiler can do things like "Named Return Value Optimization" (link) which completely avoids the copy constructor in many return value scenarios. In order to enforce calling the copy constructor you'd need to write a lot of code aimed at "tricking" the C++ compiler. Not a good idea.
In a particular scenario though if you want to enforce calling the copy constructor, you can do an explicit call.
Object SomeFunc() {
Object o1 = ...
return Object(o1);
}
You should not design your class with a reliance on the copy constructor being called (or not called) in specific circumstances. The compiler is allowed to elide or add copy constructor calls at all sorts of places, and you really don't want to have to keep track of them.
As for why you need one - well, the compiler may decide it needs a copy, and the copy constructor is what it uses to do so. The advantage of copy constructor calls being elided is performance - copying is usually quite an expensive operation.
Is this the problem ?
OuterClass(const OuterClass & rhs)
{
std::cout << "OuterClass Constructor" << std::endl;
==>
std::cout << "OuterClass Copy Constructor" << std::endl;
}
OuterClass & operator=(const OuterClass & rhs)
{
std::cout << "OuterClass Constructor" << std::endl;
==>
std::cout << "OuterClass Assignment operator" << std::endl;
}
A copy paste error!
I would suggest you to debug the code once to see what exactly is happening. Debugging really helps you to find the problems.
EDIT: for inner class issue:
As others have already pointed out this is the case of The Name Return Value Optimization(NRVO).
InnerClass innerClass()
{
InnerClass ic;
std::cout << "innerClass() method" << std::endl;
return ic;
}
the compiler can transforms the function to
void innerClass( InnerClass &namedResult)
{
std::cout << "innerClass() method" << std::endl;
}
Thus it eliminates both the return by value of the class object and the need to invoke the class copy constructor.
Please go through below two links to understand more on NRVO:
MSDN NRVO
Stan Lippman's BLog
Object o1(); doesn't create any objects rather it defines a function prototype with function name o1, void arguments and return type as Object. You need to post some code to find the actual problem.
Post some code. I think you are using some incorrect syntax.
The copy constructor must exactly have the following signature:
MyObject(const MyObject&)
Then you can see if the copy constructor is called with the following code:
MyObject m1;
MyObject m2(m1);
You are not allowed to use MyObject m1(); that is a function declaration.