我想实现一个结构,它在按值返回大型结构时更有效,使用未命名的临时('prvalue')作为默认的形式参数。首先,我将展示它将解决的性能问题的一个例子:
如果我们有结构:
struct BIG_STRUCT
{
char aArray[260];
char aArray1[260];
} ;
一个初始化它的临时函数然后按值返回它的函数:
BIG_STRUCT Func()
{
BIG_STRUCT sTemp;
/*init sTemp*/
return sTemp; // or BIG_STRUCT(sTemp) // constructs the return value by using a temporary
}
我相信现在您已经看到了性能问题的位置 - 在堆栈上创建了2个BIG_STRUCT副本 - 1用于临时用于“构造”返回值,1用于返回值本身。同样在return语句中,调用'copy constructor'来使用临时值初始化返回值。因此浪费了内存和执行时间。现在您可能会想为什么不通过引用返回?但是这将导致悬挂引用,因为函数临时值在它们所属的函数范围的末尾被“破坏”(即使引用是'rvalue',它也不会起作用)。例如:
BIG_STRUCT & /* or 'rvalue' one - '&&' */ Func()
{
BIG_STRUCT sTemp;
/*init sTemp*/
return sTemp; // return a local by reference - resulting in dangling reference
}
这个问题的解决方案正如我在开头所说的那样,通过在函数调用时自己创建返回值临时值,使用未命名的变量作为类型为'rvalue'引用的默认形式参数,并再次返回'rvalue'引用这个对象。所以'BIG_STRUCT Func()'的优化版本将如下所示:
BIG_STRUCT &&Func(BIG_STRUCT &&result = BIG_STRUCT())
{
//BIG_STRUCT sTemp;
/*init result*/
return (BIG_STRUCT&&)result; //converts 'lvavlue' to 'xvalue'
}
这将与函数实际返回值但没有性能问题的方式相同。这种结构只有一个问题,即函数返回一个'rvalue'引用,所以如果我们将它的返回值赋给'rvalue'引用,它的生命周期就不会被延长,这将导致一个悬空引用。我的意思是新标准允许我们通过将它们分配给'rvalue'参考来延长'prvalues'的生命周期。但是我们在当前示例中没有返回一个,所以这样的代码将无效:
BIG_STRUCT && refPrvalue = Func();
refPrvalue.aArray[3] = 0; //unknown result accessing dangling reference
任何解决方案我该如何解决这个问题?
答案 0 :(得分:1)
我认为你可能误解了C ++ 11中按价值返回的方式。
返回具有自动存储持续时间的本地对象将被编译器自动视为rvalue(这是标准所要求的)。
MyObject func() {
MyObject o;
return o; // Return value will be move constructed.
}
这是因为编译器知道在退出作用域时o
是要被破坏的。因此,在这种情况下明确地将右值传递给return
是错误的,例如
return std::move(o); // Wrong, 'o' is implicitly converted to rvalue.
事实上,这将禁止RVO(见下一段),因此是一种悲观情绪。
此外,所有大多数现代编译器都将使用RVO(返回值优化),这将确保返回值在呼叫站点构建。 E.g。
MyObject func() {
return {}; // Further simplification. Default constructs return value.
}
int main() {
MyObject o = func(); // You can almost be sure that no copies are made.
// 'o' is constructed directly at call site (RVO).
// Worst case scenario, one move is performed.
}