C++11移动构造函数优化

C++11 Move constructor optimization

本文关键字:优化 构造函数 移动 C++11      更新时间:2023-10-16

我目前正在尝试挂起move构造函数。我发现了以下(使用g++ d.cpp --std=c++11 -O3编译)

class A {
    string _x;
public:
  A(string x) { cout << "default contrsutctor: " << x << "n"; _x = x; }
  A(const A& other) { cout << "copy contrsutctor: " << other._x << "n"; _x = other._x;  }
  A(A&& other) { cout << "move contrsutctor: " << other._x << "n"; _x = other._x;  }
  A foo() {
    cout << "foo: " << _x << "n";
    return A("foo");
  }
};
int main()
{
  A a;
  A b = a;
  b.foo();
}

我希望这个输出:

default contrsutctor: a
move contrsutctor: a
foo: a
default contrsutctor: foo

但是输出是:

default contrsutctor: a
copy contrsutctor: a
foo: a
default contrsutctor: foo

为什么A b = a行没有优化为使用move构造函数?之后永远不会使用a对象,所以优化代码以使用它而不是复制构造函数是安全的。

我知道我可以强制使用std::move()调用move构造函数,但我更希望在这种情况下自动调用。

为什么A b=A行没有优化为使用move构造函数?

您可以在复制构造函数和移动构造函数中执行的操作可能完全不同。编译器不能保证这两个构造函数的结果是相同的。实现这种优化有可能改变程序的行为,从而打破"好像"规则。

您需要使用std::movea强制转换为A&&:

#include <utility>
int main()
{
  A a("a");
  A b = std::move(a);
  b.foo();
}

移动构造函数的正确实现应该是:

A(A&& other)
: _x(std::move(other._x))
{}

A b = std::move(a);行之后,a应为"空"。在这种情况下,a._x将为空 正如@TonyD在评论中指出的那样,a._str可能处于未指定但有效的状态(移动std:string的构造函数)。在这一行之后,应谨慎使用a

A b = a;总是调用复制构造函数,无论它是否可以调用移动构造函数。此外,对象a的生存期在分配之后继续,即使它不再被使用。

如果你想使用move构造函数,你必须明确它:

A b = std::move(a);

请注意,这可能很危险,因为移动后a仍然可以访问。如果您以后不小心使用了它,可能会出现未定义的行为。

想想为什么它会自动发生。在您给出的示例中,没有必要,因为您还可以使用a而不是b。在许多更有意义的情况下,移动构造函数/赋值将自动使用,例如A a; a = foo();

为什么A b=A行没有优化为使用move构造函数?

因为这将改变程序的可观察行为。编译器不允许自由更改程序的可观察行为(§1.9/1),除非在非常特殊的情况下(§12.8/31)。这不是这些情况之一。从构造函数中删除副作用,编译器可能会对其进行优化。当然,如果你去掉了副作用,那么你就不会注意到编译器是否优化了构造函数调用(除非你检查了程序集或二进制输出),但这就是重点。