【发布时间】:2015-10-09 05:01:06
【问题描述】:
考虑以下代码:
struct Foo
{
Foo() { cout << "Foo()\n"; }
~Foo() { cout << "~Foo()\n"; }
Foo(Foo&) { cout << "Foo(Foo&)\n"; }
Foo(Foo&&) { cout << "Foo(Foo&&)\n"; }
int d;
};
struct Bar
{
Foo bigData;
void workOnBigData() { /*...*/ }
}
Foo getBigData()
{
Bar b;
b.workOnBigData();
return b.bigData;
}
就复制省略/移动语义而言,实现getBigData() 的最佳方式是什么?在这个实现中,编译器似乎不允许移动bigData。我测试了以下功能:
Foo f()
{
Foo foo;
return foo; // RVO
}
Foo g()
{
Bar b;
return b.bigData; // Copy
}
Foo h()
{
Bar b;
auto r = move(b.bigData);
return r; // Move
}
您能解释一下这些实现的结果,并展示返回本地对象成员的最有效方法吗?
【问题讨论】:
-
对于命名返回值优化,调用者必须在调用函数之前保留一些堆栈空间。然后,该内存将用于构造被调用者的本地对象,返回语句变为无操作。因此,NRVO 不能应用于子对象,只能应用于完整对象(它有额外的限制)。
-
Automatic move on return 是一种优化,它改变了程序的可观察行为。它是保守地引入的,即仅适用于允许应用 NRVO 的情况(但编译器不能)和其他一些极端情况。如果没有介绍,那么人们可能经常写
return std::move(x);,即使x可以通过NRVO返回;但是move(x)阻止了 NRVO,所以这将是一种悲观(对于仅移动类型,return x还必须检查移动 ctor,如果应应用 NRVO)。 -
@dyp 这是否意味着,当 NRVO 无法应用时,
return std::move(x)应用于强制执行返回移动(在这些情况下无法自动完成)? -
哦,由于CWG 1579,C++11 中的“极端情况”在 C++14 中得到了放松。 -- “当 NRVO 不能应用时” 取决于你所说的“不能应用”。如果它可能不会被应用,那么你应该
move。如果它可能被应用,请不要move。但我猜 C++14 规则更容易:move除非你的 return 语句是return name;其中name是本地(非静态)变量或函数参数。
标签: c++ c++11 move-semantics rvo