同一行初始化时std::move为何调用拷贝构造而非移动构造?
std::move Triggers Copy Constructor Instead of Move Constructor Hey there! Let's break down what's going wrong here—this is a super common mix-up between move constructors and move assignment operators, so let's unpack it step by step.
First, the Critical Mistake in Your Code
Looking at the code you labeled as a "move constructor":
Foo& operator=(Foo&& other) //move ctor. I'm not sure whether this can be used as a move ctor { if (other.i != nullptr)... }
This isn't a move constructor at all—it's a move assignment operator!
A proper move constructor has a completely different signature: it's a constructor (no return type, name matches the class) that takes an rvalue reference to the class type. Here's what it should look like:
Foo(Foo&& other) // Valid move constructor { // Transfer ownership of the dynamic resource i = other.i; other.i = nullptr; // Leave the source object in a safe, empty state }
Why std::move Is Calling the Copy Constructor
When you do "same-line initialization" (like Foo new_foo = std::move(existing_foo);), this is an initialization operation, not an assignment. Initialization always invokes a constructor, never an assignment operator.
Since you haven't defined a valid move constructor, the compiler falls back to the only constructor that can handle the argument: your user-defined copy constructor (Foo(Foo const&)).
Also, remember that in C++11 and later, if you explicitly define a copy constructor or copy assignment operator, the compiler will not automatically generate a move constructor for you—you have to write it yourself.
Fixing the Code
Here's the corrected version with a proper move constructor, plus a polished move assignment operator (to handle actual assignment cases) and adherence to the Rule of Five:
class Foo { public: int* i = nullptr; // Initialize member to avoid garbage values Foo() = default; // Copy constructor Foo(Foo const& other) { if (other.i != nullptr) i = new int(*other.i); } // Copy assignment operator (fixed to avoid memory leaks) Foo& operator=(Foo const& other) { // Clean up existing resource first delete i; i = nullptr; if (other.i != nullptr) i = new int(*other.i); return *this; } // Proper move constructor (no return type) Foo(Foo&& other) noexcept { // Transfer ownership of the pointer i = other.i; other.i = nullptr; } // Proper move assignment operator Foo& operator=(Foo&& other) noexcept { // Clean up existing resource first delete i; // Transfer ownership i = other.i; other.i = nullptr; return *this; } // Destructor to prevent memory leaks ~Foo() { delete i; } };
A few key improvements here:
- Added a destructor to follow the Rule of Five (essential for managing dynamic memory)
- Marked move operations as
noexcept(this helps the compiler optimize, especially for containers likestd::vector) - Fixed the copy assignment operator to delete existing resources first (prevents memory leaks)
Once you add the proper move constructor, using std::move in initialization will trigger it instead of the copy constructor.
内容的提问来源于stack exchange,提问作者Thomas Martin

