编译器忽略显式定义的移动构造函数
compiler ignores explicitly-defined move constructor?
我试图理解为什么下面的代码没有调用我的move构造函数。我使用gnu++11进行编译。
#include <iostream>
class Foo{
int value;
public:
Foo(int v){ value = v; }
Foo(const Foo& g){
value = g.value;
std::cout << "copy construct calledn";
}
Foo(Foo&& g){
value = g.value;
std::cout << "move construct calledn";
}
int getValue() const{ return value; }
};
Foo operator+(const Foo& f, const Foo& g){
Foo h(f.getValue() + g.getValue());
return h;
}
void sayValue(const Foo& f){
std::cout << f.getValue() << std::endl;
}
int main(){
Foo f(5);
sayValue(f + f);
return 0;
}
运行以下代码只需打印10
而不是
move construct called
10
正如我所期望的那样。我期望这样做的原因是,当我为Foo定义+二进制运算符时,如果我理解正确的话,返回Foo g应该调用move构造函数。
这是因为编译器只是通过忽略我的移动构造函数定义来进行优化,还是因为我的一个假设有缺陷?
在C++中有一个概念叫做省略。
Elision允许编译器将各种变量的生命期连接到一个生命期中——它们的存在被忽略在一起。
它可以省略用于直接构造相同类型值的临时变量,也可以省略从简单return x;
风格语句中的函数返回的命名局部变量。
使其合法的构造函数必须存在,但编译器不需要调用它。即使复制或移动构造函数会产生副作用,也允许发生Elision,因此您的print语句不会运行。
所以编译器没有移动——它只是直接构建了它要去的对象!值h
实际上是+
的实际返回值。
你做过吗
Foo x = f+f;
编译器可以将h
、+
和x
的返回值消除为一个对象。
有两种常见的情况可以追溯到一段时间前,即NRVO和RVO(命名为返回值优化和返回calue优化),但它们只是编译器要消除的特定技术的名称。编译器不被强制省略,但被允许省略。在某些情况下,省略对编译器来说很困难(在一种情况下,IIRC是不允许的);在每种情况下,都可以调用move ctor(如果不存在move,则可以调用copy)。一个例子是,当您有两个不同的局部变量从一个函数返回时;这使得编译器很难合法地消除这两个返回值。
Foo operator+(const Foo& f, const Foo& g){
Foo h(f.getValue() + g.getValue());
return h;
}
这调用了NRVO,并绕过了使用move构造函数返回对象的需要。
相关文章:
- 为什么不调用移动构造函数?(默认情况下只有构造器,没有别的)
- std::vector::p ush_back() 不会在 MSVC 上编译具有已删除移动构造函数的对象
- 仅包含可移动 std::map 的类的移动构造函数不起作用
- 为什么调用复制构造函数而不是移动构造函数?
- 基类中的默认析构函数禁用子类中的移动构造函数(如果有成员)
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 移动构造函数和右值引用
- 为什么 std::memmove 中联合的默认非平凡移动构造函数C++?
- 具有专用化的模板类中的可靠条件复制和移动构造函数
- C++:为什么不调用移动构造函数?
- 移动构造函数永远不会被调用
- C++:关于使用 Stroustrup 示例移动构造函数/赋值的问题
- 运算符+ 的规范实现涉及额外的移动构造函数
- C ++为什么在移动构造函数中需要移动/前进
- 为什么在删除"移动构造函数"时使用"复制构造函数"?
- 为什么这里不调用移动构造函数?
- 隐式移动构造函数
- 如何为具有私有成员的派生类实现移动构造函数
- 为什么不调用移动构造函数
- 是否可以避免在以下代码中复制/移动构造函数的需要?