Home >Backend Development >C++ >Why is the C 11 Move Constructor Not Called When a Temporary Object is Used to Initialize Another Object?
Description:
When working with move semantics in C 11, it's possible to encounter scenarios where the move constructor is unexpectedly skipped in favor of the default constructor. This article explores this issue, examines the underlying reasons, and provides solutions.
Problem:
Consider the following class X with constructors that output messages:
<code class="cpp">class X { public: explicit X(char* c) { cout << "ctor" << endl; init(c); } X(X& lv) { cout << "copy" << endl; init(lv.c_); } X(X&& rv) { cout << "move" << endl; c_ = rv.c_; rv.c_ = nullptr; } const char* c() { return c_; } private: void init(char *c) { c_ = new char[strlen(c)+1]; strcpy(c_, c); } char* c_; };</code>
In the sample usage provided below, we create three objects:
<code class="cpp">X x("test"); cout << x.c() << endl; X y(x); cout << y.c() << endl; X z( X("test") ); cout << z.c() << endl;</code>
However, instead of the expected output showing the move constructor being called for z, the default constructor is used instead.
Standard Conformity:
According to the C 11 standard (§12.8.32), move semantics should be preferred over copy semantics whenever possible. So, the move constructor should indeed be called for z in this case.
Explanation of Behavior:
The observed behavior is due to a compiler optimization called copy elision. C 11 allows compilers to omit copying/moving objects in certain situations to improve performance. One of these situations is when a temporary object would be copied/moved to an object with the same cv-unqualified type.
In the last line of our sample code, X("test") creates a temporary X object and it has the same cv-unqualified type as the target (z). Therefore, the compiler is allowed to elide the copy and move constructors, directly constructing the temporary object into z without invoking either constructor.
Solution:
To force the move constructor to be called, we can use std::move() to explicitly indicate that the move should take place:
<code class="cpp">X z( std::move(X("test")) );</code>
With this modification, the expected output is produced, confirming the involvement of the move constructor.
The above is the detailed content of Why is the C 11 Move Constructor Not Called When a Temporary Object is Used to Initialize Another Object?. For more information, please follow other related articles on the PHP Chinese website!