I have the following code:
#include <stdio.h>
class Foo {
public:
int a;
~Foo() { printf("Goodbye %d\n", a); }
};
Foo newObj() {
Foo obj;
return obj;
}
int main() {
Foo bar = newObj();
bar.a = 5;
bar = newObj();
}
When I compile with g++ and run it, I get:
Goodbye 32765
Goodbye 32765
The number printed seems to be random.
I have two questions:
Why is the destructor called twice?
Why isn't 5 printed the first time?
I'm coming from a C background, hence the printf, and I'm having trouble understanding destructors, when they are called and how a class should be returned from a function.
Let's see what happens in your main function :
int main() {
Foo bar = newObj();
Here we just instantiate a Foo and initialize it with the return value of newObj(). No destructor is called here because of copy elision: to sum up very quickly, instead of copying/moving obj into bar and then destructing obj, obj is directly constructed in bar's storage.
bar.a = 5;
Nothing to say here. We just change bar.a's value to 5.
bar = newObj();
Here bar is copy-assigned1 the returned value of newObj(), then the temporary object created by this function call is destructed2, this is the first Goodbye. At this point bar.a is no longer 5 but whatever was in the temporary object's a.
}
End of main(), local variables are destructed, including bar, this is the second Goodbye, which does not print 5 because of previous assignment.
1 No move assignment happens here because of the user-defined destructor, no move assignment operator is implicitly declared.
2 As mentioned by YSC in the comments, note that this destructor call has undefined behavior, because it is accessing a which is uninitialized at this point. The assignment of bar with the temporary object, and particularly the assignment of a as part of it, also has undefined behavior for the same reasons.
1) It's simple, there are two Foo objects in your code (in main and in newObj) so two destructor calls. Actually this is the minimum number of destructor calls you would see, the compiler might create an unnamed temporary object for the return value, and if it had done that you would see three destructor calls. The rules on return value optimization have changed over the history of C++ so you may or may not see this behaviour.
2) Because the value of Foo::a is never 5 when the destructor is called, its never 5 in newObj, and though it was 5 in mainit isn't by the time you get to the end of main (which is when the destructor is called).
I'm guessing your misunderstanding is that you think that the assignment statement bar = newObj(); should call the destructor, but that's not the case. During assignment an object gets overwritten, it doesn't get destroyed.
I think one of the main confusions here is object identity.
bar is always the same object. When you assign a different object to bar, you don't destroy the first one - you call operator=(const& Foo) (the copy assignment operator). It is one of the five special member functions that can be auto-generated by the compiler (which it is in this case) and just overwrites bar.a with whatever is in newObj().a. Provide your own operator= to see that/when this happens (and to confirm that a is indeed 5 before this happens).
bar's destructor is only called once - when bar goes out of scope at the end of the function. There is only one other destructor call - for the temporary returned by the second newObj(). The first temporary from newObj() is elided (the language allows it in this exact case because there is never really a point to creating and immediately destroying it) and initializes bar directly with the return value of newObj().
Related
if I have something along the lines of:
auto foo=Foo(Bar())
where Foo's constructor takes a const reference to Bar, is there some way to ensure that Bar's destructor will not get called before the destructor on foo at the end of the scope of foo, so that the reference to Bar will still be valid even in foo's destructor?
The relative order of the destructors is guaranteed.
auto foo=Foo(Bar());
Since Bar() is a temporary, then it is guaranteed to be destructed at the end of the expression: aka the semicolon. You are absolutely guaranteed that the Bar is destroyed before foo.
There is no way to extend the lifetime of this temporary, you'll have to make a copy of it (potentially by moving it). Alternatively:
{
Bar b;
auto foo=Foo(b);
}
Since the objects in a single scope are destroyed in the opposite order they're constructed, then since these are in the same scope, b will be destroyed after foo is destroyed.
I was trying to create an instance of an object with private constructor. Is this method correct?
#include <iostream>
using namespace std;
class A{
int y;
A(int y=2):y(y){};
public:
A(const A &obj){
cout<<"copy Cotr is called"<<endl;
this->y=obj.y;
}
int* addr(){
int *a=&y;
return a;
}
static A create(int y1=2){
class A a(y1);
cout<<&a<<endl;
return a;
}
void print(){
cout<<y<<endl;
}
};
int main(){
A o1=A::create(1);
A o2=A::create(3);
cout<<&o1<<" "<<&o2<<endl;
return 0;
}
The output is:
0x7ffd20d2f280
0x7ffd20d2f284
0x7ffd20d2f280 0x7ffd20d2f284
In the above code, I fail to understand few points:
create() returns a value, so during assignment which take place in A o1=A::create(1);, copy constructor should be called but it isn't. why?
Is this some undefined behavior as the address of the object created in create() and in main() are same and the object in create() is local and goes out of scope after the function ends.
create() returns a value, so during assignment which take place in A o1=A::create(1);, copy constructor should be called but it isn't. why?
You have copy-elision (Demo) which is an optimization allowed by standard.
The object is directly constructed in final place and no copy/move is done.
Some copy-elisions is even mandatory in C++17. (half of them in your case).
Is this some undefined behavior as the address of the object created in create() and in main() are same and the object in create() is local and goes out of scope after the function ends.
With copy elision, as object is directly constructed in final place, there is indeed only one address, it is as-if the local variable of create was the one from main.
This:
A a = x();
is different than this:
A a;
a = x();
In the second case you have a copy, in the first you don't.
To answer your second question, the object created in create() is local all right, but then it's copied back to the caller (actually, moved). Since the stack frame is the same, the local address is the same. But when it's copied, you have two different objects.
Thanks for all the answers. Dug deep into it and now answering my own question.
For the learned:
This is major instance of copy elision in C++ 17.
Answer ends for you. For the one who still didn't understood:
This method has no errors and do not show any undefined behavior. Most of the compilers uses C++11 or C++17 these days which is well integrated with copy elision(copy omission).
create() returns a value, so during assignment which take place in A
o1=A::create(1);, copy constructor should be called but it isn't. why?
Copy constructor is not called as the return type is prvalue(pure rvalue) and the compiler optimizes the program in such a way that the return value is created directly into the storage where the function's return value would otherwise be copied or moved to. So, actually no move or copy takes place so no move/copy constructor is called. Even after the end of create() destructor too is not called.
Is this some undefined behavior as the address of the object created
in create() and in main() are same and the object in create() is local
and goes out of scope after the function ends.
So, even after the function create() ends, the object dont get pushed out of scope or the destructor for that object is not called. As the object is created in not in the create() but in the main() itself. It is not an undefined behavior but a major benefit of C++ as unnecessary pointers and functions need not to be declared or invoked. Here, NRVO takes place.
In a return statement, when the operand is the name of a
non-volatile object with automatic storage duration, which isn't a
function parameter or a catch clause parameter, and which is of the
same class type (ignoring cv-qualification) as the function return
type. This variant of copy elision is known as NRVO, "named return
value optimization".
I have looked at different sources with regard to the internal implementation of auto_ptr<> and auto_ptr_ref<>. I have this question that I couldn't figure out why.
.... When returning a 'auto_ptr' from a function, the compiler finds that there is no suitable ctor to copy construct the returned object. But there is conversion to 'auto_ptr_ref' and ctor taking an 'auto_ptr_ref' constructing an 'auto_ptr'. Thus, the compiler creates an 'auto_ptr_ref' which basically just holds a reference to the original 'auto_ptr' and then constructs an 'auto_ptr' from this object. That's all (well, when returning an object, the compiler goes through this process normally twice because the returned value is copied somewhere but this does not change the process)....
(Reference http://www.josuttis.com/libbook/auto_ptr.html)
In this example, I emulate the implementation of auto_ptr<> and auto_ptr_ref<> and is able to generate results showing that compiler indeed goes through the process twice
The example has these basic traits:
1) A's copy constructor does NOT take const reference.
2) A has conversion operator B
3) A has constructor A(B);
class B {
};
class A {
public:
A () {
printf("A default constructor() # %p\r\n", this);
}
A(B) {
printf("constructor(B) # %p\r\n", this);
}
A (A &a) {
printf("copy constructor(non-const) # %p\r\n", this);
}
operator B() {
printf("A convertion constructor(B) # %p\r\n", this);
return B();
}
};
A foo()
{
return A();
}
int main()
{
A a(foo());
}
So when A a(foo())) is executed
1) foo() generates temporary object X
2) X is converted to type B
3) constructor A(B) is used to construct object a
This is output:
A default constructor() # 0xbfea340f
A convertion constructor(B) # 0xbfea340f
constructor(B) # 0xbfea344f
A convertion constructor(B) # 0xbfea344f
constructor(B) # 0xbfea344e
We can see that compiler wen through the conversion-construct steps 2&3 twice.
Why is that?
If you are calling a function which returns a class type, basically the following happens:
On the call, the calling function reserves some space for the temporary return value on the stack (it has to be done by the calling function because anything the called function allocates on the stack gets deallocated as soon as the function returns). It passes the address of that space to the called function.
On executing the return statement, the called function constructs the return value from the argument given to the return statement into the space provided by the calling function. In your case, that argument is the temporary A value.
After the function returns, the caller uses the temporary value the called function constructed to do whatever the code demands. In your case, you use it to construct a local variable from it.
So you construct a new object of type A from an existing one twice: First, to construct the temporary return value (whose life time persists after the function foo returns, until the end of the declaration) from the explicitly generated temporary in the return statement (whole lifetime ends on the end of the full expression, that is in this case equivalent to on return from foo). And second, to initialize the local variable a from the temporary returned by foo.
Of course, due to no appropriate copy constructor being available, in both cases you go through the B conversions. This works because the return does a direct initialization, and for a you explicitly coded such a direct initialization.
Class A is being created 3 times. Once as a temporary, and copied twice. Other compilers might return different results, based on their optimization settings.
return A() creates a temporary A, and then copies it to the returned A This first copy is the first time that you see steps 2 and 3.
Then A a(foo()); copies the return from foo() into the variable in main. Triggering steps 2 and 3 again.
The following code was compiled and run in Visual Studio 2012 Express for Windows Desktop, as a learning exercise.
#include <cstdio>
class X
{
public:
X() { printf("default constructed\n"); }
~X() { printf("destructed\n");}
X(const X&) { printf("copy constructed\n"); }
X(X&&) { printf("move constructed\n"); }
X & operator= (const X &) { printf("copy assignment operator\n"); }
};
X A() {
X x;
return x;
}
int main() {
{
A();
}
std::getchar();
}
When compiled with compiler optimizations disabled (/Od), the resulting output indicates that the destructor is called twice. This is a problem given that only one object is constructed. Why is the destructor being called twice? Wouldn't this be a problem if the class was managing it own resources?
default constructed
move constructed
destructed
destructed <<< Unexpected call
I tried a couple of experiments to try and explain the output, but ultimately these didn't lead to any useful explanations.
Experiment 1: When the same code is compiled with optimizations enabled (/O1 or /O2), the resulting output is:
default constructed
destructed
which indicates that the Named Return Value Optimization has elided the call to the move constructor, and masked the underlying problem.
Experiment 2: Disabled the optimization and commented out the move constructor. The output generated was what I expected.
default constructed
copy constructed
destructed
destructed
Keep in mind that when an object is the source of a move operation it will still be destroyed. So the source of the move needs to put itself in a state such that being destructed will not release resources that it no longer owns (since they were moved to another object). For example, any raw pointers (that will now be owned by the move constructed object) in the source object should be set to NULL.
The X in A is destroyed when it goes out of scope.
A returns a temporary object (constructed from X by the move constructor) which is a separate instance. This is destroyed in the caller's scope. That will cause the destructor to be called again (on the temporary).
The move constructor was picked because the compiler detected that X was going to be destroyed immediately afterward. To use this approach, the move constructor should nullify or reset any data in the original object so that the destructor will not invalidate any data that has been taken over by the destination of the move.
When you pass an rvalue by value, or return anything by value from a function, the compiler first gets the option to elide the copy. If the copy isn’t elided, but the type in question has a move constructor, the compiler is required to use the move constructor.
http://cpp-next.com/archive/2009/09/move-it-with-rvalue-references/
When you exit from the scope in which the temporary object was created, it is destroyed. If a reference is bound to a temporary object, the temporary object is destroyed when the reference passes out of scope unless it is destroyed earlier by a break in the flow of control.
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fcplr382.htm
The RVO can produce different behavior from the non-optimized version:
Return value optimization, or simply RVO, is a compiler optimization technique that involves eliminating the temporary object created to hold a function's return value.[1] In C++, it is particularly notable for being allowed to change the observable behaviour of the resulting program.[2]
http://en.wikipedia.org/wiki/Return_value_optimization
Although Michael's and jspcal answers are accurate, they didn't answer the heart of my question, which was why were there two destructor calls made. I was expecting just one.
The answer is that function A() returns a temporary object. Always. This is how function return values work, and move-semantics has no bearing on this fact. I guess Michael and jspcal assumed that I had not missed such a basic fact. I equated the term "moved" with the concept of "swap". When swapped, objects are not constructed and destructed. Hence I was expecting just one destructor call.
Since the returned object must be constructed and destructed, the second destructor call was made (and a second constructor call).
Now, the actual constructor selected to be executed depends on what is provided in the class definition. If a move-constructor is available, that will be called. Otherwise the copy constructor will be called.
The following code calls the destructor 4 times:
#include<iostream>
using namespace std;
class A{
public:
A(){cout<<"A"<<endl;}
~A(){cout<<"~A"<<endl;}
A f(){cout<<"F"<<endl; A b; return b;}
};
int main(){
A a,b;
b=a.f();
}
OUTPUT:
A
A
F
A
~A
~A
~A
~A
Can some one please explain?
I was thinking that there should be only three destructor calls.
There are two objects in main(), so the destructor will be called two times just because of them. One object in f(), so the destructor will be called one time just because of it. Total 3 times (which you expect, but read on...)
Now the fourth time destructor is called for the temporary object which is created when returning from f. This can happen only when there is no RVO at all. RVO is compiler's choice which means it may optimize it, or it may not. The language doesn't give any guarantee of RVO.
Anyway, just increase your optimization level; I'm sure you will see at most 3 destructor invocations only.
There are 2 objects in main: A a,b;, one object in the body of function f() : A b; and then there is temporary object that is being copied and its copy stored into b.
When returning b in the body of your function, copy is created at first, then the local b is destructed, then copy is assigned into variable b declared in main and then this copy is destructed.
Add following line to class A definition and see yourself:
A(const A&) { cout << "copying" << endl; }
With Named Return Value Optimization, the compiler tries to eliminate redundant Copy constructor and Destructor calls which means that local b from the function f() will be assigned into variable b in main without copy being created. So with RVO / NRVO only 3 objects are created in your case.
Although there is a way how to avoid destructing this copy without RVO in your case:
A a;
A b = a.f();
in this case copy of return value of function f() is created and stored as a variable b. Which also means that no assigment operator is called and only 2 objects are created in main: a and copy of b returned by f().
Hope this helps.
Your compiler didn't optimize it. Have you compiled it with optimizations enabled?
Here is the output of the same code, compiled with gcc:
A
A
F
A
~A
~A
~A
There is one hidden creation and destruction of an instance of A: when you're returning from function f(), a temporary copy of object b is created. It's assigned to b in main() and then destroyed.
You can't rely on RVO to occur. That's why you should never put functional logic inside destructors or copy constructors (yes, those too can be elided).
Return value optimization is just something the standard allows, but does not enforce.
With no optimization or O2, I too get 4 destructor callse.
With full optimization - Ox - I only get 3.
Local variable in f is copied into a temporary variable when the function returns. That is why there are four destructor calls. (Copy operation calls the copy constructor A(A&) not your default constructor A(), hence three As.)