请考虑以下几点:
struct A { /* ... */ };
A foo() {
auto p = std::make_pair(A{}, 2);
// ... do something
return p.first;
}
auto a = foo();p.first是复制、移动还是RVO-ed?
发布于 2015-10-26 11:43:27
我在Visual 2010和gcc-5.1RVO是而不是应用中找到的(例如,参见http://coliru.stacked-crooked.com/a/17666dd9e532da76)。
标准的相关部分为12.8.31.1 class.copy。它声明允许复制省略(我的突出显示):
在具有类返回类型的函数中的返回语句中,当表达式是非易失性自动对象名称时(函数参数或由处理程序(except.handle)的异常声明引入的变量除外),其类型与函数返回类型相同(忽略cv限定),则可以通过将自动对象直接构造到函数的返回值中来省略复制/移动操作。
由于p.first不是对象的名称,因此禁止使用RVO。
发布于 2015-10-26 13:48:05
为了增加一点燃料,如果RVO发挥作用,这个功能会如何发挥呢?调用者已经将A的一个实例放在内存中的某个地方,然后调用foo来分配给它(更好的是,假设A是更大的结构的一部分,让我们假设它是正确对齐的,这样结构的下一个成员就在A实例之后)。假设RVO正在运行,p的p部分位于调用方想要它的位置,但是second的int在哪里被放置呢?为了保持A的正常工作,它必须紧跟在pair实例之后,但是在源位置,在A实例之后还有其他一些成员。
我希望RVO不会发生在这个地方,因为您只是返回一个较大对象的一部分。移动可能发生,因为first将不得不留在一个可毁灭的状态。
发布于 2015-10-26 11:52:02
@atkins首先给出了答案。只是添加这个小测试程序,您可能会发现,在今后跟踪移动/分配行为时有用。
#include <iostream>
#include <string>
using namespace std::string_literals;
struct A {
A()
: history("created")
{
}
A(A&& r)
: history("move-constructed,"s + r.history)
{
r.history = "zombie: was "s + r.history;
}
A(const A& r)
: history("copied from: " + r.history)
{
}
~A() {
history = "destroyed,"s + history;
std::cout << history << std::endl;
}
A& operator=(A&& r) {
history = "move-assigned from " + r.history + " (was "s + history + ")"s;
r.history = "zombie: was "s + r.history;
return *this;
}
A& operator=(const A&r ) {
history = "copied from " + r.history;
return *this;
}
std::string history;
};
A foo() {
auto p = std::make_pair(A{}, 2);
// ... do something
return p.first;
}
auto main() -> int
{
auto a = foo();
return 0;
}示例输出:
destroyed,zombie: was created
destroyed,move-constructed,created
destroyed,copied from: move-constructed,createdhttps://stackoverflow.com/questions/33344259
复制相似问题