假设我有一个带有副本,移动构造函数,默认构造函数
的类node
Node func (Node n){
return n;
}
Node newN = func(Node{}); //#2
然后这些被叫多少次?
移动constuctor:一次在#2。
复制构造函数怎么样?
答案 0 :(得分:3)
最好是一个建筑和一个移动建筑。
#include <iostream>
using std::cout;
using std::endl;
class Something {
public:
Something() {
cout << __PRETTY_FUNCTION__ << endl;
}
Something(Something&&) {
cout << __PRETTY_FUNCTION__ << endl;
}
Something(const Something&) {
cout << __PRETTY_FUNCTION__ << endl;
}
};
Something foo(Something in) {
return in;
}
int main() {
Something something = foo(Something{});
(void) something;
}
上面的输出是这个
Something::Something()
Something::Something(Something &&)
Something
对象的构造产生一个prvalue,它是RVO的候选者,这将被省略为foo()
的函数参数。如果使用C ++ 17进行编译,无论如何都将省略,但是当您使用C ++ 11和C ++ 14进行编译时,只有在不使用-fno-elide-constructors
编译标志禁止使用elisions时,才会省略此操作。
但是,当您从函数返回该对象时,标准不允许NRVO发生。明确禁止从函数参数中删除(请参阅下面的标准中的确切引用)。所以发生了一个移动(假设你有一个移动构造函数,如果你没有移动构造函数,那么就会发生一个复制)
所以总共允许你有一个构造和一个移动构造(如果没有定义移动构造函数,那么你得到一个副本)
§15.8.3复制/移动省略[class.copy.elision]
- 醇>
当满足某些条件时,允许实现省略类对象的复制/移动构造,...
- 在具有类返回类型的函数中的
中return
语句中,当表达式是非易失性自动对象的名称时(除了函数参数或引入的变量之外)通过处理程序(18.3)的 exception-declaration 与函数返回类型相同的类型(忽略cv-qualification),可以省略复制/移动操作通过将自动对象直接构造到函数调用的返回对象
正如您所看到的,语言不允许从函数参数中省略,因此会发生移动。
另请注意,如果显式删除移动构造函数,则此代码将无法编译