请考虑以下代码:
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
}
您能否解释这些实现的结果,并显示返回本地对象成员的最有效方法。
答案 0 :(得分:3)
有很多方法可以避免额外的副本,更接近你的代码的是imho:
Foo getBigData()
{
Foo ret; // do a cheap initialization
Bar b;
b.workOnBigData();
std::swap(ret, b.bigData); // 'steal' the member here
return ret; // NRVO can apply
}
通过移动构造返回对象
可以实现同样的目的Foo getBigData()
{
Bar b;
b.workOnBigData();
Foo ret(std::move(b.bigData)); // these two lines are equivalent to
return ret; // return std::move(b.bigData);
}
答案 1 :(得分:1)
我认为这个问题Why isn't the copy constructor elided here?的答案在回答你的问题时非常有用。您的示例中未使用复制省略
Foo getBigData()
{
Bar b;
b.workOnBigData();
return b.bigData;
}
因为这个要求没有完整填写(http://en.cppreference.com/w/cpp/language/copy_elision):
return语句的表达式是非易失性对象的名称 有自动存储时间...... 并且具有相同的类型(忽略顶级cv资格) 函数的返回类型,然后省略复制/移动
在您的示例中,Bar是一个具有自动存储持续时间但是返回Foo的变量。如果更改Bar类,编译器将开始使用copy elision:
#include <iostream>
#include <typeinfo>
using namespace std;
struct Foo
{
Foo() { cout << "Foo()\n"; }
~Foo() { cout << "~Foo()\n"; }
Foo(const Foo&) { cout << "Foo(Foo&)\n"; }
Foo(Foo&&) { cout << "Foo(Foo&&)\n"; }
int d;
};
struct Bar
{
Foo bigData;
void workOnBigData() { /*...*/ }
};
struct Bar2
{
void workOnBigData(Foo&) { /*...*/ }
};
Foo getBigData()
{
Bar b;
b.workOnBigData();
return b.bigData;
}
Foo getBigData2()
{
Foo f;
Bar2 b;
b.workOnBigData(f);
return f;
}
int main()
{
{
Foo f = getBigData();
}
cout << "---" << endl;
{
Foo f = getBigData2();
}
}
#include <iostream>
#include <typeinfo>
using namespace std;
struct Foo
{
Foo() { cout << "Foo()\n"; }
~Foo() { cout << "~Foo()\n"; }
Foo(const Foo&) { cout << "Foo(Foo&)\n"; }
Foo(Foo&&) { cout << "Foo(Foo&&)\n"; }
int d;
};
struct Bar
{
Foo bigData;
void workOnBigData() { /*...*/ }
};
struct Bar2
{
void workOnBigData(Foo&) { /*...*/ }
};
Foo getBigData()
{
Bar b;
b.workOnBigData();
return b.bigData;
}
Foo getBigData2()
{
Foo f;
Bar2 b;
b.workOnBigData(f);
return f;
}
int main()
{
{
Foo f = getBigData();
}
cout << "---" << endl;
{
Foo f = getBigData2();
}
}
这是它输出的内容:
$ ./a.out
Foo()
Foo(Foo&)
~Foo()
~Foo()
---
Foo()
~Foo()