C++ 优化 : avoid a copy operation

标签 c++ compiler-optimization move-semantics copy-elision

我有以下内容:

#include <iostream>
#include <utility>

class T {
public:
    T() {std::cout << "Default constructor called" << std::endl;}
    T(const T&) {std::cout << "Copy constructor called" << std::endl;}
};

static T s_t;

T foo() {
    return s_t;
}

class A {
public:
    A() = delete;
    A(T t) : _t(t) {}
private:
    T _t;
};

int main() {

    std::cout << "Starting main" << std::endl;
    A a(foo());
    return 0;

}

当我用以下行编译它时: g++ -std=c++17 -O3 test.cpp 并运行它,我得到以下输出

Default constructor called
Starting main
Copy constructor called
Copy constructor called

我的问题是:由于 A 的构造函数采用类型为 T 的右值对象,该对象仅用于初始化 _t ,编译器是否可以避免第二次复制操作,直接将s_t复制到_t中?

(我知道我可以通过为 T 实现 move 构造函数来用 move 替换第二个拷贝)

最佳答案

您的复制构造函数具有可观察到的副作用(输出)。 C++ 优化的(几乎)黄金法则是假设规则:不得更改可观察到的副作用。但是这个规则的两个异常(exception)之一是省略了一些复制操作,在此处指定:

http://eel.is/c++draft/class.copy.elision

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects.

但这只在非常特殊的情况下才允许:

This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

  • in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object [...]

您的变量没有自动存储持续时间(即它不是局部变量)。

  • in a throw-expression, [...]

我们不是抛出表达式。

  • in a coroutine [...]

我们不在协程中。

  • when the exception-declaration of an exception handler ([except]) declares an object of the same type (except for cv-qualification) as the exception object ([except.throw]) [...]

也不是这样的。

这里既没有涉及从函数返回全局变量,也没有涉及使用构造函数参数来初始化成员变量,因此任何编译器在您显示的代码中省略这些拷贝都是非法的。

就是说,如果编译器可以证明没有副作用(在大多数编译器的情况下,包括系统调用和内存分配),当然可以根据 as-if 规则随意删除拷贝,就像所有其他优化一样。

关于C++ 优化 : avoid a copy operation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58119586/

相关文章:

c++ - 硬盘读取的性能问题

c++ - Opengl 选择性 glClipPlane

LLVM、-fprofile-instr-generate、对“__llvm_profile_register_function”的 undefined reference

c++ - C/C++ 优化器能否决定延迟评估仅用于短路评估的值?

c++ - 使用继承 move 分配/构造函数会抛出范围外的错误

c++ - 同一对象的双 move 是从左向右复制吗?

c++ - 在 std::move'ing 时警告调用复制构造函数

c++ - 控制 lambda 的生命周期

c++ - 将 std 字符串转换为 const char*

c++ - 当 GCC 明确表示会减慢程序速度时,为什么要在 O2/O3 处启用优化?