复制省略可见的副作用

copy elision visible side effect

考虑这段代码:

#include <iostream>

using namespace std;

struct Foo {
public:
    int _a{};
    Foo(int a) : _a{a} 
    {
        std::cout << "ctor" << std::endl;
    }

    Foo(const Foo &)
    {
        std::cout << "copy" << std::endl;
    }
};

int main () {
    Foo a{10};
    Foo b = 10;
    std::cout << b._a << std::endl;
}

当我用

编译时

g++ -std=c++11 -fno-elide-constructors test.cpp

输出是

ctor ctor copy 0

这正是我所期望的,因为 Foo b = 10 中的 10 是从 int 隐式构造的,那么 b 是从 Foo 复制构造的.此外,我的复制构造函数没有做任何事情,所以成员 _a 仍然是 0 (因为它是 in-class-initialized)。

但是,当我使用复制省略时

g++ -std=c++11 test.cpp

输出是

ctor ctor 10

这至少可以说是令人惊讶。我知道这里省略了复制构造函数,但这是一个严重的副作用(成员一次被初始化为 0,一次被初始化为 10),因为它会影响代码路径的其余部分。

这种行为正常吗?

在特定情况下将复制省略作为优化的全部意义在于允许消除复制构造的副作用。也就是说,是的,尽管复制构造函数 and/or 析构函数具有副作用,但它预计会发生复制省略。

如果您不希望在某些情况下发生复制省略,您需要安排它被禁止。在您的特定情况下,禁止复制省略确实有点烦人,但像这样的事情应该可以解决问题:

template <typename T>
T const& inhibit(T const& ref) {
    return ref;
}
// ...
Foo b = inhibit<Foo>(10);