是否可以确保省略副本
Is it possible to ensure copy elision?
复制省略是一种巧妙的优化技术,在某些情况下,依赖复制省略实际上比"手动"传递引用更快。
因此,让我们假设您已经确定了一个关键的代码路径,在该路径中,您依赖于这样一个事实,即复制省略是由编译器为代码路径执行的,以获得最大性能。
但是现在您依赖于编译器优化。
是否有任何(显然是编译器特定的)方法来确保实际执行副本省略,并在无法执行副本省略时让编译器(或其他工具)生成警告/错误?
(我在想一些与Visual C++的__forceinline
非常相似的东西,如果编译器没有内联标记的函数,就会生成警告。)
否。
但是你可以写一个等价的,虽然完全不可读的代码:
BigObj f()
{
BigObj x(g());
x.someMethod();
return x;
}
//...
BigObj z = f();
//...
翻译(省略副本)为:
void f(BigObj* obj)
{
new(obj) BigObj(g());
obj->someMethod();
}
//...
char z[sizeof(BigObj)];
f((BigObj*)&z[0]);
//...
((BigObj*)&z[0])->~BigObj();
但说真的,只要以编译器可以消除副本的方式编写代码即可。即只返回一个没有分支的对象:
BigObj f()
{
BigObj x, y;
// use x and y
if(condition)
return x;
else
return y;
// cannot be elided
}
BigObj f()
{
if(condition)
{
BigObj x;
return x;
}
else
{
BigObj y;
return y;
}
// can be elided
}
不是真的,只是在复制构造函数中放入一个assert(false);
。
否则,请使用您最喜欢的探查器来衡量应用程序中有趣的部分是否足够快。
在C++1z(预计2017年)中,某些情况下需要保证副本省略:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html
根据公共cppreference.com编译器功能支持wiki GCC 7+和Clang 4+,请确保这一点。
幸运的是,优化方面不需要启用新的语言支持,因为这是一个纯粹的优化(遵循旧的语言标准)。
此外,当应用优化时,允许复制构造函数不可用可能需要在编译期间启用较新的语言标准,或者使用不要求严格一致性的松散或扩展模式(例如,潜在的GCC的-fpermissive
)。
是否有任何(显然是编译器特定的)方法来确保复制省略实际上是执行的,并让编译器(或另一个工具)生成警告/错误执行?
gcc (trunk)
(尚未发布v14)具有-Wnrvo
";如果编译器没有在[class.copy.elision]允许的上下文中消除从局部变量到函数返回值的副本,则发出警告。这种省略通常称为命名返回值优化"
gcc (trunk)
在上可用https://godbolt.org/
- 如何确保C++函数在定义之前声明(如override关键字)
- 用callgrind追踪不必要的副本
- 如何确保在使用基于布尔值的两个方法之一调用方法时避免分支预测错误
- 使用Unique_ptr确保工厂中的对象唯一
- 关于:C++中异常对象的范围:为什么我没有得到副本?
- MESI协议和std::atomic-它是否确保所有写入立即对其他线程可见?
- C++需要帮助从用户那里获得一个整数,并确保它在另外两个整数之间
- 确保流程关闭
- 在为LINUX创建共享库时,如何避免STL的私有/弱副本
- 检查注册表项是否链接到(或副本)另一个注册表项
- 为什么构建目录中新构建的共享库与安装目录中的副本具有不同的依赖项集?
- C++基于范围的 for 循环和元素副本
- 如何确保接受的C++模板类型使运算符重载?
- 创建提升::shared_ptr的深层副本
- 确保编译时的特定 std::array 位置
- 如何从构造函数副本 T(const T&)调用对象 T?
- 副本初始化的默认模板参数推导
- C++深浅的副本
- 如何确保将对象通过许多层的组件时,不会制作副本
- 是否可以确保省略副本