是否可以确保省略副本



复制省略是一种巧妙的优化技术,在某些情况下,依赖复制省略实际上比"手动"传递引用更快。

因此,让我们假设您已经确定了一个关键的代码路径,在该路径中,您依赖于这样一个事实,即复制省略是由编译器为代码路径执行的,以获得最大性能。

但是现在您依赖于编译器优化。

是否有任何(显然是编译器特定的)方法来确保实际执行副本省略,并在无法执行副本省略时让编译器(或其他工具)生成警告/错误?

(我在想一些与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/

最新更新