【问题标题】:std::unique_ptr destructor constructor orderstd::unique_ptr 析构函数构造函数顺序
【发布时间】:2018-07-28 06:16:32
【问题描述】:

我想知道当我将新的 unique_ptr 分配给先前的 unique_ptr 时,会发生什么。在下面的代码中:

std::unique_ptr<my_class> test;
......
test = std::unique_ptr<my_class>(new my_class());
......
test = std::unique_ptr<my_class>(new my_class());

我希望当我第二次分配一个新的 std::unique_ptr 进行测试时,首先调用 my_class 的析构函数,然后调用它的构造函数。 我的预期有误吗? 但是当我调试我的代码时,我看到的是相反的。调用 my_class 的第一个构造函数,然后调用它的析构函数。

【问题讨论】:

  • @seccpur 是的,我现在就这样做了,但我想知道为什么会这样
  • 如果第二个构造函数调用抛出异常,你会发生什么?顺便说一句:您问题中的unique_ptr 是一个红鲱鱼,这里没有适用的特殊规则。
  • @UlrichEckhardt 构造函数或析构函数不能抛出异常。
  • 不错的猜测,但是错了。
  • @UlrichEckhardt 简短的回答是,在构造函数中扔东西是危险的。 link。我不记得了,但我读过一些从不会在构造函数或析构函数中抛出异常的书。

标签: c++ std


【解决方案1】:

在前一个实例的析构函数之前调用构造函数的原因是因为您将 new my_class() 作为参数传递给 unique_ptr 的构造函数。首先评估参数,构造一个新的 unique_ptr 实例,该实例拥有新创建的对象的所有权,然后将该新的 unique_ptr 实例分配给旧的实例。

因此,它所拥有的旧 unique_ptr 的 my_class 对象将被释放并销毁,调用 my_class 析构函数。

实际上和你写的一样:

my_class* temp = new my_class;
test = std::unque_ptr<my_class>(std::move(temp));

这里直接可见新对象是先构造的。

【讨论】:

    【解决方案2】:

    来自cppreference

    unique_ptr&amp; operator=( unique_ptr&amp;&amp; r ) noexcept; (1)
    template&lt; class&gt; U, class E &gt; unique_ptr&amp; operator=( unique_ptr&lt;U,E&gt;&amp;&amp; r ) noexcept; (1)

    将所有权从r 转移到*this,就像通过调用 reset(r.release()) 后跟 get_deleter() 的赋值来自 std::forward&lt;E&gt;(r.get_deleter()).

    如您所见,reset 在前一个指针上被调用,它执行以下操作:

    1. 保存当前指针old_ptr = current_ptr的副本
    2. 用参数current_ptr = ptr覆盖当前指针
    3. 如果旧指针非空,则删除先前管理的对象 if(old_ptr != nullptr) get_deleter()(old_ptr)

    【讨论】:

    • @nader 添加到答案中
    猜你喜欢
    • 1970-01-01
    • 2020-01-20
    • 2012-04-10
    • 2016-03-18
    • 1970-01-01
    • 2017-03-12
    • 1970-01-01
    • 2013-06-24
    相关资源
    最近更新 更多