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

为何将const引用返回值std::move后仍能触发对象移动构造?

问题:const右值为何触发了移动构造?

Table::get_subtable()返回内部SubTable对象的const引用,将其通过std::move传入按值接收参数的静态工厂函数from_subtable后,结果触发了移动构造(见输出)。按直觉,移动构造函数无法从const&&构造对象,应该触发编译错误或拷贝构造,想知道哪里理解有误?

代码示例

#include <iostream>

struct SubTable {
    SubTable() = default;

    SubTable(SubTable&& other) {
        std::cout << "Moved subtable" << std::endl; 
    }

    SubTable(const SubTable&) = default;

    static auto from_subtable(SubTable subtable) -> SubTable; 
};

auto SubTable::from_subtable(SubTable subtable) -> SubTable
{
    return subtable;
}

struct Table {
    SubTable _subtable;
    auto get_subtable() const -> const SubTable&;
};

auto Table::get_subtable() const -> const SubTable& {
    return _subtable;
}

int main()
{
    Table hello;
    auto subtable = SubTable::from_subtable(std::move(hello.get_subtable()));
}

输出

Moved subtable

解答

你的误解在于触发移动构造的时机:你看到的输出并不是参数传递阶段产生的,而是函数返回阶段的行为,具体拆解如下:

  1. 参数传递阶段:
    std::move(hello.get_subtable())将const左值引用转换为const SubTable&&类型,但你的SubTable并没有定义接受const SubTable&&的构造函数,因此编译器会退而求其次调用默认拷贝构造函数(const SubTable&&可以隐式绑定到const SubTable&参数)。这一步没有输出,因为你给拷贝构造函数加了= default,没有自定义输出逻辑。

  2. 函数返回阶段:
    在from_subtable函数中,return subtable;返回的是函数的局部参数(左值)。根据C++标准,当返回的是函数的局部对象(或参数)时,编译器会自动将其视为右值,优先调用移动构造函数。这就是你看到的Moved subtable输出的来源。

  3. 验证方式:
    若给拷贝构造函数添加输出逻辑:

    SubTable(const SubTable&) {
        std::cout << "Copied subtable" << std::endl;
    }
    

    运行后会得到如下输出,清晰展示两个阶段的行为:

    Copied subtable
    Moved subtable
    
  4. 补充说明:
    若想让const SubTable&&直接触发移动构造,需要显式定义SubTable(const SubTable&&)构造函数,但这种做法几乎没有实际意义——移动构造的核心是“窃取”对象资源,而const右值无法被修改,根本无法完成资源窃取操作,因此标准库和常规代码中几乎不会定义这类构造。

内容的提问来源于stack exchange,提问作者glades

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 00:23:10