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

2024-01-12

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;,移动向量正在构建t2 in main,然后从返回的临时get_test被破坏,那么t2 in main被摧毁了。

我不明白的是:按值返回时不应该有复制构造函数调用吗?也就是说,我认为get_test应该复印t然后这个副本被移入t2。这好像是t被移入t2马上。


C++17

从C++17开始,有强制复制埃利森 https://en.cppreference.com/w/cpp/language/copy_elision#Mandatory_elision_of_copy/move_operations其中说:

在以下情况下,编译器需要省略类对象的复制和移动构造,即使复制/移动构造函数和析构函数具有可观察到的副作用。这对象直接构建到存储中,否则它们将被复制/移动到。复制/移动构造函数不需要存在或可访问:

  • In the 当初始化表达式是纯右值时,对象的初始化与变量类型具有相同的类类型(忽略 cv 限定):

(强调我的)

这意味着t2直接从构造prvalue that get_test返回。并且自从一个prvalue用于构造t2,使用移动构造函数。请注意,在 C++17 中,标志-fno-elide-constructors没有影响返回值优化(RVO) 与 NRVO 不同。


C++17 之前的版本

但在 C++17 之前,有非强制性副本埃利森 https://en.cppreference.com/w/cpp/language/copy_elision#Mandatory_elision_of_copy/move_operations既然你已经提供了-fno-elide-constructors标志,临时的prvalue由返回get_test使用移动构造函数。所以你会看到对 move ctor 的第一个调用。然后,该临时文件用于初始化t2再次使用移动构造函数,因此我们第二次调用移动构造函数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

这里不应该有一个复制者调用吗?禁用省略(无命名返回值优化) 的相关文章

随机推荐