You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

同一行初始化时std::move为何调用拷贝构造而非移动构造?

Why 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 like std::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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:31:36