An unexpected call to the destructor occurs when connected to the constuctor movement

The following code was compiled and run in Visual Studio 2012 Express for Windows Desktop as a training 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"); } }; XA() { X x; return x; } int main() { { A(); } std::getchar(); } 

When compiling with the compiler disabled (/ Od), the resulting output indicates that the destructor is called twice. This is a problem in which only one object is built. Why is the destructor called twice? Wouldn't it be a problem if the class managed its own resources?

 default constructed move constructed destructed destructed <<< Unexpected call 

I tried a couple of experiments to try to explain the solution, but in the end it did not lead to any useful explanations.

Experiment 1. When the same code is compiled with optimizations enabled (/ O1 or / O 2), the resulting output:

 default constructed destructed 

which indicates that Optimization with the lowest return value rejected the call to the move constructor and masked the main problem.

Experiment 2: Turn off optimization and comment on the move constructor. The output was what I expected.

 default constructed copy constructed destructed destructed 
+1
c ++ c ++ 11 move-semantics visual-c ++ visual-studio-2012
source share
3 answers

Although Michael and jspcal's answers are accurate, they did not answer my question, so there were two calls to the destructor. I was expecting only one.

The answer is that the function A () returns a temporary object. Always. This is how function return values ​​work, and move-semantics does not affect this fact. Michael and jspcal probably suggested that I did not miss such a basic fact. I equated the term "move" to the concept of "swap". When replacing objects are not created or destroyed. Therefore, I expected only one call to the destructor.

Since the returned object must be constructed and destroyed, a second call to the destructor (and a second call to the constructor) was made.

Now the actual constructor selected for execution depends on what is provided in the class definition. If the move constructor is available, this will be called. Otherwise, the copy constructor will be called.

+2
source share

Keep in mind that when an object is the source of a move operation, it will still be destroyed. Thus, the source of the movement must put itself in a state, so that the destruction will not free up resources that it no longer has (since they were moved to another object). For example, any raw pointers (which will now belong to a movable constructed object) in the original object must be set to NULL.

+7
source share

X in is destroyed when it goes out of scope.

A returns a temporary object (built from X by the move constructor), which is a separate instance. This is destroyed in the caller area. This will cause the destructor to be called again (on temporary).

The move constructor was chosen because the compiler found that X would be destroyed right after that. To use this approach, the move constructor must invalidate or reset any data in the original object, so the destructor will not invalidate any data that was captured by the move destination.

When you pass an rvalue value by value or return something by value from a function, the compiler first gets the option to exclude the copy. If the copy has not been deleted, but the type in question has a move constructor, the compiler should use the move constructor.

http://cpp-next.com/archive/2009/09/move-it-with-rvalue-references/

When you exit the area in which the temporary object was created, it is destroyed. If the link is attached to a temporary object, the temporary object is destroyed when the link goes out of scope, if it was not previously destroyed by a break in the control flow.

http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fcplr382.htm

RVO can create different behaviors from a non-optimized version:

Return value optimization or just RVO is a compiler optimization method that involves removing a temporary object created to store the return value of a function. [1] In C ++, it is particularly noteworthy that it is allowed to change the observed behavior of the resulting program. [2]

http://en.wikipedia.org/wiki/Return_value_optimization

+3
source share

All Articles