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(使用前将#替换为@)