保证复制省略不应该适用吗?
Shouldn't guaranteed copy elision apply?
我不明白 gcc 在这里的行为,我希望 RVO 适用,但无论我是否传递优化标志和/或传递-std=c++17
,在第二种情况下,无端的大括号似乎阻止了 GCC 省略副本。
$ cat /tmp/foo.cc
#include <iostream>
#define PING() std::cerr << __PRETTY_FUNCTION__ << 'n'
struct foo
{
foo() { PING(); }
~foo() { PING(); }
foo(const foo&) { PING(); }
};
foo bar()
{
PING();
foo res;
return res;
}
foo baz()
{
PING();
{
foo res;
return res;
}
}
int main()
{
foo f1 = bar();
foo f2 = baz();
}
$ g++-mp-7 -std=c++17 -O3 foo.cc
$ ./a.out
foo bar()
foo::foo()
foo baz()
foo::foo()
foo::foo(const foo&)
foo::~foo()
foo::~foo()
foo::~foo()
这不应该是保证复制的一部分吗? Clang的行为符合我的预期:
$ clang++-mp-4.0 foo.cc
$ ./a.out
foo bar()
foo::foo()
foo baz()
foo::foo()
foo::~foo()
foo::~foo()
来自 https://en.cppreference.com/w/cpp/language/copy_elision
在以下情况下,即使复制/移动(自 C++11(构造函数和析构函数具有可观察到的副作用,编译器也允许,但不需要省略类对象的复制和移动(自 C++11 起(构造。这是一个优化:即使它发生了并且没有调用 copy-/move-constructor,它仍然必须存在并且可访问(好像根本没有发生优化(,否则程序格式不正确。
- 如果函数按值返回类类型,并且 return 语句的表达式是具有自动存储持续时间的非易失性对象的名称,该对象不是函数参数或 catch 子句参数,并且与函数的返回类型具有相同的类型(忽略顶级 cv-限定(,则省略复制/移动(自 C++11 以来(。构造该本地对象时,它直接在存储中构造,否则函数的返回值将被移动或复制到该存储中。这种复制省略的变体称为NRVO,即"命名返回值优化"。
NRVO 不能保证会发生,但在您的情况下是可能的。
正如Sander De Dycker在评论中指出的那样, 已经有一个错误报告来获得这个Elision的机会。
RVO(返回值优化(仅在从函数返回临时值时适用。 在bar
和baz
您都不会返回临时。 相反,您返回一个命名对象。 这意味着您正在处理 NRVO(命名返回值优化(,这是无法保证的,而且更难做到。 两个输出都符合标准,只是 clang 在优化方面比 gcc 做得更好。
相关文章:
- 条件断点在不应该触发时触发
- 你好。。。id_public变量不应该给出结果为 81 和 86 吗?为什么它为两个派生类占用不同的内存位置?
- 为什么我不应该把所有东西都放在标题中?
- 找不到 QRegularExpression 行为的任何解释。它有效,但不应该
- 在清除 istream 之前,我不应该需要取消获取它吗?
- 通过基类接受方法转发派生 UniquePtr 的右值会移动引用而不是复制
- c++ 为什么我不应该从不同的线程解锁互斥锁
- 除了 std::vector 之外,是否有一个 std 容器不会复制和销毁作为类的元素?
- "typename"不应该只在模板函数或模板类中使用吗?
- 为不应该获得未定义行为的内容获取未定义的行为
- 调用值构造函数而不是复制构造函数
- 两种情况下的输出不应该相同吗?
- 如何在C++中分配嵌套的protobuf而不进行复制
- 默认情况下,"std::shared_ptr"不应该使用"std::d efault_delete"吗?
- 指定不用作复制构造函数的复制构造函数
- 为什么编译器使用移动构造函数而不是复制构造函数
- 编译器在不需要复制构造函数时关心复制构造函数
- 保证复制省略不应该适用吗?
- 特征库:为什么我的函数在不应该复制我的参数时复制我的参数?
- 在什么情况下,运算符=应该用左值/右值重载而不是复制和交换来实现