c++ - 这里不应该有一个复制者调用吗?禁用省略(无命名返回值优化)

标签 c++ move copy-constructor copy-elision nrvo

struct Test {
    int field = 30;
    Test() { cout << "In ctor" << endl; }
    Test(const Test &other) { field = other.field; cout << "In copy ctor" << endl; }
    Test(Test &&other) { field = other.field; cout << "In move ctor" << endl; }
    Test &operator=(const Test &other) { field = other.field; cout << "In copy assignment" << endl; return *this; }
    Test &operator=(Test &&other) { field = other.field; cout << "In move assignment" << endl; return *this; }
    ~Test() { cout << "In dtor" << endl; }
};

Test get_test() {
    Test t;
    return t;
}

int main() {
    Test t2 = get_test();
}

我认为这是典型的 NRVO 示例。我正在使用 -fno-elide-constructors 进行编译,我看到调用了以下内容:ctor、move ctor、dtor、dtor。

所以第一个ctor调用对应于行Test t;,move ctor正在main中构造t2,然后是临时的从 get_test 返回的内容被销毁,然后 main 中的 t2 被销毁。

我不明白的是:按值返回时不应该有复制构造函数调用吗?也就是说,我认为 get_test 应该制作 t 的拷贝,然后将该拷贝移至 t2 中。看起来 t 立即移至 t2 中。

最佳答案

C++17

从C++17开始,有mandatory copy elison其中说:

Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible:

  • In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:

(强调我的)

这意味着 t2 是直接从 get_test 返回的 prvalue 构造的。由于使用纯右值来构造t2,因此使用了 move 构造函数。请注意,在 C++17 中,标志 -fno-elide-constructors 对返回值优化 (RVO) 没有影响,并且与 NRVO 不同。


C++17 之前版本

但在 C++17 之前,有 non-mandatory copy elison由于您提供了 -fno-elide-constructors 标志,因此 get_test 使用 move 构造函数返回临时 prvalue。所以你会看到对 move ctor 的第一个调用。然后,该临时文件用于使用 move 构造函数再次初始化 t2,因此我们得到了对 move 构造函数的第二次调用。

关于c++ - 这里不应该有一个复制者调用吗?禁用省略(无命名返回值优化),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72253869/

相关文章:

c++ - std::make_pair、std::unordered_map 和从键类型 move 构造函数的用法

c++ - 通用 Windows 平台 - CustomHidDevice(错误 : Value is blocked)

Java每0.5秒在动画中 move jlabel

c++ - 检查 qprocess 是否已经完成

c++ - 如何有效地在 std::vector 中插入一对?

c++ - 在 unique_ptr vector 中转移所有权

c++ - 模拟一个虚拟拷贝构造函数

c++ - 添加 unique_ptr 作为类的实例字段,而不是显式删除复制/赋值构造函数

C++ Eigen : spline derivatives() gives strange derivatives

c++ - 从 child 继承并调用 child 的功能在 visual studio 2013 中不起作用