繁体   English   中英

为什么对象副本要构造和破坏两次?

[英]Why is object copy constructed and destructed twice?

为什么在下面的代码中出现一对“额外”的复制构造函数和破坏?

当Dingledong的构造函数将STL容器作为参数时,就会发生这种情况(我尝试过std :: vector和std :: list)。 其他事情可能会发生吗? 如果构造方法改为使用指针,则不会发生。 如果我改为在堆上分配ding(Dingledong * ding = new Dingledong(v)),也不会发生这种情况。

#include <list>
#include <iostream>

class Dingledong{
public:
    Dingledong(std::list<int> numbers)
    {
        std::cout << "construction\n";
        numbers_ = numbers;
    }
    Dingledong(Dingledong const& other)
    {
        std::cout << "COPY construction\n";
    }
    ~Dingledong()
    {
        std::cout << "destructed\n";
        // I would do some cleanup here.. unsubscribe from events, whatever..
        // but the destructor is called sooner than I would expect and thus
        // the cleanup is done prematurely.
    }
    std::list<int> numbers_;
};

void diller()
{
    std::cout << "diller started.. " << std::endl;
    std::list<int> v = std::list<int>(34);
    // Having an STL container as parameter in constructor causes Dingledong's copy constructor to 
    // be used to create a temporary Dingledong which is immediately destructed again. Why?
    Dingledong ding = Dingledong(v);
    std::cout << "Has ding been destructed?\n";
}

int main()
{
    diller();
    system("pause");
}

输出:

diller started...
construction
COPY construction     // I didn't expect this to happen
destructed            // I didn't expect this to happen
Has ding been destructed?
destructed

先感谢您!

这段代码:

Dingledong ding = Dingledong(v);

手段:

  1. 创建类型为Dingledong临时对象,使用v初始化
  2. 创建使用临时对象初始化的对象ding

复制构造函数在此处进入步骤2。 如果您不想要副本,请不要编写指定副本的代码。 例如:

Dingledong ding(v);   // no copy

编译器可以实现一个称为复制省略的功能,其中可以优化此临时对象(即使复制构造函数具有副作用),但它们不必这样做,在这种情况下,没有理由依赖于此。


您可以通过添加move-constructor来改进代码,在这种情况下(如果编译器不执行复制省略),该操作将是移动而不是复制,从而降低了成本。

也有浪费拷贝构造函数( numbers从复制v ,然后numbers_从复制numbers ,也numbers_被初始化,然后分配,而不是仅仅被初始化)。 这将是一个更好的构造函数:

Dingledong(std::list<int> numbers): numbers_( std::move(numbers) )
{
    std::cout << "construction\n";
}

您的输出:

diller started...
construction                //(1)
COPY construction           //(2)
destructed                  //(3)
Has ding been destructed?
destructed                  //(4)

和相关的代码位:

Dingledong ding = Dingledong(v);

Dingledong(v)创建一个临时对象。 (1)被打印。

您将此临时对象分配给ding(实际上,这是调用复制构造函数的语法糖)。 (2)被打印。

语句完成后,临时对象将被销毁。 (3)打印。 您的代码将运行,并且一旦ding超出范围,它将被销毁,将打印(4)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM