将 -fno-elide-constructors 标志传递给编译器时的副本数

Number of copies when -fno-elide-constructors flag is passed to the compiler

提问人:Luckk 提问时间:12/13/2022 更新时间:12/13/2022 访问量:34

问:

请考虑以下类:

struct IntPointerWrapper 
{
    int* data_pointer;

    IntPointerWrapper() : data_pointer(new int()) 
    {
        std::cout << "IntPointerWrapper()" << std::endl;
    }

    IntPointerWrapper(const IntPointerWrapper& other) : data_pointer(new int())
    {
        std::cout << "IntPointerWrapper(const IntPointerWrapper& other)" << std::endl;
        *data_pointer = *other.data_pointer;
    }

    IntPointerWrapper& operator=(const IntPointerWrapper& other)
    {
        std::cout << "operator=(const IntPointerWrapper& other)" << std::endl;
        *data_pointer = *other.data_pointer;
        return *this;
    }
    
    ~IntPointerWrapper() 
    { 
        std::cout << "~IntPointerWrapper() " << std::endl;
        delete data_pointer; 
    }
};

还有一个简单的工厂方法

IntPointerWrapper bar() 
{
    IntPointerWrapper q;
    return q;
}


int main()
{
    IntPointerWrapper m = bar();
}

我想使用禁用的复制省略进行编译,以查看复制构造函数被调用了多少次。

我得到这个输出:

IntPointerWrapper()
IntPointerWrapper(const IntPointerWrapper& other)
~IntPointerWrapper() 
IntPointerWrapper(const IntPointerWrapper& other)
~IntPointerWrapper() 
~IntPointerWrapper() 

所以复制构造函数被调用了两次,但我真的不明白为什么。在运行这个实验之前,我敢打赌一个电话就足够了。

我想知道这 2 个副本而不是单个副本背后是否有任何动机,或者它只是特定于实现的东西。

我尝试了 Clang、GCC 和 MSVC,得到了相同的结果。

C++ 构造函数 复制 省略

评论


答:

3赞 NathanOliver 12/13/2022 #1

IntPointerWrapper bar() 
{
    IntPointerWrapper q;
    return q;
}

您可以复制到函数的返回对象中。这是你的第一个副本。然后你有q

IntPointerWrapper m = bar();

它将返回的值从 中复制到 ,因此这是您的第二个复制操作。bar()m


应该注意的是,这两个副本只发生在 C++17 之前。从 C++17 开始,我们保证了复制省略,这摆脱了发生在 并且只有返回对象的副本的副本。你可以在这个实时示例中看到这种差异IntPointerWrapper m = bar();