Unexpected destructor call occurs when paired with move constuctor - c++

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.

Related

Where (in memory) does copy constructor copy the return value of function?

From what I've learned so far about C++, copy constructor is called in 3 situations
When object is passed by value
When a function returns an object.
When object is declared and initialized with another object of same type.
#include "Cube.h"
using uiuc::Cube;
Cube foo()
{
Cube c;
return c; //copy constructor is invoked (BUT where is this copied value stored?)
}
int main()
{
Cube c2 = foo(); // copy constructor is invoked yet again !!!
return 0;
}
In the above code, copy constructor is invoked two times.
First time for return c; and Second time for Cube c2 = foo();
I have three questions
Where is returned object c copied to?
Why does not the constructor directly store (copy) the returned object(i.e c) in c2 ? Would not it be more efficient?
If the returned object c is not being stored in some variable like c2, why is the copy constructor still invoked?
In the above code, copy constructor is invoked two times
If your type has a move constructor, it will be used instead of the copy constructor in this case.
In any case, here the move (or copy) constructor is called 0 or 1 times depending on compiler optimizations (could also be 2 times before C++17).
You start with 2 moves: first c is moved to a temporary object, then that temporary object is moved to c2.
The second move can be optimized away, this is called RVO. This optimization is mandatory starting with C++17.
The first move can be optimized away as well, but compilers are not required to do it. This is called NRVO.
When a move (or copy) is "optimized away", it's achieved by making the source and the destination the same object. So, e.g. if both RVO and NRVO happen, c and c2 become the same object.
Where is returned object c copied to?
Why does not the constructor directly store (copy) the returned object(i.e c) in c2 ?
If RVO and NRVO don't happen, it's moved to a temporary object.
If RVO happens, it's moved to c2.
If both RVO and NRVO happen, c2 and c are the same object, so no moves are needed.

Scope of variable local to static method in C++

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".

how does returning an object work with assignment operator?

Assume we have the following operation:
Object a = b.copy();
copy() is basically a method which copies an object and returns its copy.
Object copy()
{
Object copied_Object;
/..do the copy../
return copied_Object;
}
At first I thought the return would trigger an assignment operator = and place
the result at the right field of the operation, but it turned out that actually the copy constructor gets activated and then the Object created inside the function gets destroyed. This is what I know.
My question is, can you explain to me step by step what happens when Object a = b.copy(); is executed?
Object a = b.copy();
Is an instruction to create/construct/initialize an Object. No assignment is involved.
Assignments looks like this,
object = something;
Notice the absence of a declaration of object.
Now
Object a = b.copy();
constructs a, by a b.copy() of type Object, this requires Object to have the ability to be constructed by another Object. This is of course the copy constructor. Either the compiler generated, or a defaulted, or an explicit copy constructor.
When the statement is executed, the copy function will execute and transfer the created copied_Object to the caller by either
Copy construction
Copy elision, the compiler will invoke its black-magic box and construct Object a in-place. No copy construction necessary. As hinted by Jarod.
As LogicStuff, suggests you can do
Object copy()
{
return *this;
}
This copies the contents of the b object to the return value and requires a copy constructor.
I'll steal Daniel H's comment too and conclude that
Object a = b;
will carry the exact same semantics under normal circumstances. I.e. circumstances of least surprise.

Efficiency difference between copy and move constructor

C++11 introduced a new concept of rvalue reference. I was reading it somewhere and found following:
class Base
{
public:
Base() //Default Ctor
Base(int t) //Parameterized Ctor
Base(const Base& b) //Copy Ctor
Base(Base&& b) //Move Ctor
};
void foo(Base b) //Function 1
{}
void foo(Base& b) //Function 2
{}
int main()
{
Base b(10);
foo(b); -- Line 1 (i know of ambiquity but lets ignore for understanding purpose)
foo(Base()); -- Line 2
foo(2) ; -- Line 3
}
Now with my limited understanding, my observations are as follows :
Line 1 will simply call the copy constructor as argument is an lvalue.
Line 2 before C++11 would have called copy constructor and all those temporary copy stuff, but with move constructor defined, that would be called here.
Line 3 will again call move constructor as 2 will be implicitly converted to Base type (rvalue).
Please correct and explain if any of above observation is wrong.
Now, here'r my questions :
I know once we move an object it's data will be lost at calling location. So, i above example how can i change Line 2 to move object "b" in foo (is it using std::move(b) ?).
I have read move constructor is more efficient than copy constructor. How? I can think of only situation where we have memory on heap need not to be allocated again in case of move constructor. Does this statement hold true when we don't have any memory on heap?
Is it even more efficient than passing by reference (no, right?)?
First on your "understandings":
As I can see it, they are in principle right but you should be aware of Copy elision which could prevent the program from calling any copy/move Constructor. Depends on your compiler (-settings).
On your Questions:
Yes you have to call foo(std::move(b)) to call an Function which takes an rvalue with an lvalue. std::move will do the cast. Note: std::move itself does not move anything.
Using the move-constructor "might" be more efficient. In truth it only enables programmers to implement some more efficient Constructors. Example consider a vector which is a Class around a pointer to an array which holds the data (similar to std::vector), if you copy it you have to copy the data, if you move it you can just pass the pointer and set the old one to nullptr.
But as I read in Effective Modern C++ by Scott Meyers: Do not think your program will be faster only because you use std::move everywere.
That depends on the usage of the input. If you do not need a copy in the function it will in the most cases be more efficient to just pass the object by (const) reference. If you need a copy there are several ways of doing it for example the copy and swap idiom. But as a
Line 2 before C++11 would have called copy constructor and all those temporary copy stuff, but with move constructor defined, that would be called here.
Correct, except any decent optimizer would "elide" the copy, so that before C++11 the copy would have been avoided, and post C++11 the move would have been avoided. Same for line 3.
I know once we move an object it's data will be lost at calling location.
Depends on how the move constructor/assignment is implemented. If you don't know, this is what you must assume.
So, i above example how can i change Line 2 to move object "b" in foo (is it using std::move(b) ?).
Exactly. std::move changes the type of the expression into r-value and therefore the move constructor is invoked.
I have read move constructor is more efficient than copy constructor.
It can be, in some cases. For example the move constructor of std::vector is much faster than copy.
I can think of only situation where we have memory on heap need not to be allocated again in case of move constructor. Does this statement hold true when we don't have any memory on heap?
The statement isn't universally true, since for objects with trivial copy constructor, the move constructor isn't any more efficient. But owning dynamic memory isn't strictly a requirement for a more efficient move. More generally, move may can be efficient if the object owns any external resource, which could be dynamic memory, or it could be for example a reference counter or a file descriptor that must be released in the destructor and therefore re-aquired or re-calculated on copy - which can be avoided on move.
Is it even more efficient than passing by reference (no, right?)?
Indeed not. However, if you intend to move the object within the function where you pass it by reference, then you would have to pass a non-const reference and therefore not be able to pass temporaries.
In short: Reference is great for giving temporary access to an object that you keep, move is great for giving the ownership away.

Does D have a move constructor?

I am referencing this SO answer Does D have something akin to C++0x's move semantics?
Next, you can override C++'s constructor(constructor &&that) by defining this(Struct that). Likewise, you can override the assign with opAssign(Struct that). In both cases, you need to make sure that you destroy the values of that.
He gives an example like this:
// Move operations
this(UniquePtr!T that) {
this.ptr = that.ptr;
that.ptr = null;
}
Will the variable that always get moved? Or could it happen that the variable that could get copied in some situations?
It would be unfortunate if I would only null the ptr on a temporary copy.
Well, you can also take a look at this SO question:
Questions about postblit and move semantics
The way that a struct is copied in D is that its memory is blitted, and then if it has a postblit constructor, its postblit constructor is called. And if the compiler determines that a copy isn't actually necessary, then it will just not call the postblit constructor and will not call the destructor on the original object. So, it will have moved the object rather than copy it.
In particular, according to TDPL (p.251), the language guarantees that
All anonymous rvalues are moved, not copied. A call to this(this)
is never inserted when the source is an anonymous rvalue (i.e., a
temporary as featured in the function hun above).
All named temporaries that are stack-allocated inside a function and
then returned elide a call to this(this).
There is no guarantee that other potential elisions are observed.
So, in other cases, the compiler may or may not elide copies, depending on the current compiler implementation and optimization level (e.g. if you pass an lvalue to a function that takes it by value, and that variable is never referenced again after the function call).
So, if you have
void foo(Bar bar)
{}
then whether the argument to foo gets moved or not depends on whether it was an rvalue or an lvalue. If it's an rvalue, it will be moved, whereas if it's an lvalue, it probably won't be (but might depending on the calling code and the compiler).
So, if you have
void foo(UniquePtr!T ptr)
{}
ptr will be moved if foo was passed an rvalue and may or may not be moved it it's passed an lvalue (though generally not). So, what happens with the internals of UniquePtr depends on how you implemented it. If UniquePtr disabled the postblit constructor so that it can't be copied, then passing an rvalue will move the argument, and passing an lvalue will result in a compilation error (since the rvalue is guaranteed to be moved, whereas the lvalue is not).
Now, what you have is
this(UniquePtr!T that)
{
this.ptr = that.ptr;
that.ptr = null;
}
which appears to act like the current type has the same members as those of its argument. So, I assume that what you're actually trying to do here is a copy constructor / move constructor for UniquePtr and not a constructor for an arbitrary type that takes a UniquePtr!T. And if that's what you're doing, then you'd want a postblit constructor - this(this) - and not one that takes the same type as the struct itself (since D does not have copy constructors). So, if what you want is a copy constructor, then you do something like
this(this)
{
// Do any deep copying you want here. e.g.
arr = arr.dup;
}
But if a bitwise copy of your struct's elements works for your type, then you don't need a postblit constructor. But moving is built-in, so you don't need to declare a move constructor regardless (a move will just blit the struct's members). Rather, if what you want is to guarantee that the object is moved and never copied, then what you want to do is disable the struct's postblit constructor. e.g.
#disable this(this);
Then any and all times that you pass a UniquePtr!T anywhere, it's guaranteed to be a move or a compilation error. And while I would have thought that you might have to disable opAssign separately to disable assignment, from the looks of it (based on the code that I just tested), you don't even have to disable assignment separately. Disabling the postblit constructor also disables the assignment operator. But if that weren't the case, then you'd just have to disable opOpAssign as well.
JMD answer covers theoretical part of move semantics, I can extend it with a very simplified example implementation:
struct UniquePtr(T)
{
private T* ptr;
#disable this(this);
UniquePtr release()
{
scope(exit) this.ptr = null;
return UniquePtr(this.ptr);
}
}
// some function that takes argument by value:
void foo ( UniquePtr!int ) { }
auto p = UniquePtr!int(new int);
// won't compile, postblit constructor is disabled
foo(p);
// ok, release() returns a new rvalue which is
// guaranteed to be moved without copying
foo(p.release());
// release also resets previous pointer:
assert(p.ptr is null);
I think I can answer it myself. Quoting the "The Programming Language":
All anonymous rvalues are moved, not copied. A call to this ( this ) is never inserted
when the source is an anonymous rvalue (i.e., a temporary as featured in
the function hun above).
If I understood it correctly, this means that this(Struct that) will never be a copy, because it only accepts rvalues in the first place.