【问题标题】:Destructor gets called before member function when assigning unique_ptr to a reference将 unique_ptr 分配给引用时,在成员函数之前调用析构函数
【发布时间】:2015-05-31 12:24:59
【问题描述】:

我正在使用 unique_ptr,但得到了一些奇怪的结果。这是代码:

class Sniffer
{
public:
    Sniffer()
    {
        cout << "Sniffer()" << endl;
        s = "String!";
    }

    void operator()()
    {
        cout << "operator()(): " << s << endl;
    }

    ~Sniffer()
    {
        cout << "~Sniffer()" << endl;
    }

private:
    string s;
};


int main()
{
    cout << "Begin scope!" << endl;

    {
        Sniffer& h = *std::unique_ptr<Sniffer>(new Sniffer());   // 1

        //std::unique_ptr<Sniffer> p(new Sniffer());             // 2
        //Sniffer& h = *p;                                       // 2

        h();
    }

    cout << "End scope!" << endl;
    return 0;
}

我不明白为什么使用代码“1”,析构函数在 operator()() 之前被调用,而“End Scope!”根本不打印。代码不会崩溃,它会执行到最后一行,我得到的输出是:

Begin scope!
Sniffer()
~Sniffer()
operator()(): Press any key to continue . . .

另一方面,代码“2”的​​行为符合预期:

Begin scope!
Sniffer()
operator()(): String!
~Sniffer()
End scope!
Press any key to continue . . .

我使用参考的原因只是因为我觉得h()(*p)()p-&gt;operator()() 感觉更自然。谢谢。

【问题讨论】:

    标签: c++ reference destructor move-semantics unique-ptr


    【解决方案1】:

    std::unique_pointer&lt;Sniffer&gt; 是您的“1”中的临时值,因此在语句完成后被销毁。它的析构函数在到达下一条语句 (h();) 之前销毁 Sniffer 对象。 h 是一个悬空引用,所以h()(即h.operator()())的结果是未定义的。

    在您的情况“2”中,对象p 继续存在直到包含范围结束,即在语句h(); 之后

    【讨论】:

      【解决方案2】:

      因为当你这样做时

      Sniffer& h = *std::unique_ptr<Sniffer>(new Sniffer());
      

      您创建的 std::unique_ptr 对象是临时的并且已被破坏,留下一个对不再存在的对象的引用,然后您进入 undefined behavior 的土地。

      当你这样做时

      std::unique_ptr<Sniffer> p(new Sniffer());
      

      您创建了一个实际的非临时对象p,您当然可以在其生命周期内对其进行引用。

      【讨论】:

      • 你应该精确(很明显我知道但仍然知道)h 实际指向的动态对象 Sniffer 已被临时 unique_ptr 的析构函数删除
      【解决方案3】:

      1 行创建了一个临时的 unique_ptr 对象,该对象被取消引用,其结果就是引用 h 将指向的内容。然而,由于 unique_ptr 对象是一个临时对象,它的析构函数将在分号处调用(参见object lifetime)。这也将调用临时 unique_ptr 指向的 Sniffer 对象的析构函数。

      代码2 确实是您应该如何使用unique_ptr。或者甚至更好地使用 C++14 的 make_unique

      unique_ptr 的全部目的是当 unique_ptr 对象超出范围时,它指向的任何内容都会自动销毁(或被自定义删除器删除)。在1 行中,它甚至在您使用其内容之前就超出了范围。见documentation:

      std::unique_ptr 是一个智能指针,它通过指针保留对象的唯一所有权,并在 unique_ptr 超出范围时销毁该对象。

      【讨论】:

        【解决方案4】:

        在此声明中

        Sniffer& h = *std::unique_ptr<Sniffer>(new Sniffer());
        

        创建了一个std::unique_ptr&lt;Sniffer&gt; 类型的临时对象,该对象在语句执行结束时被销毁。

        因此引用h在代码块范围内无效。

        在此声明中

        std::unique_ptr<Sniffer> p(new Sniffer());             // 2
        

        对象 p 被创建并且将一直存活到代码块结束。所以参考h

        Sniffer& h = *p; 
        

        将在此范围内有效。

        【讨论】:

          猜你喜欢
          • 2012-09-28
          • 2015-12-05
          • 2015-08-05
          • 1970-01-01
          • 1970-01-01
          • 2023-03-31
          • 1970-01-01
          • 2020-04-01
          • 1970-01-01
          相关资源
          最近更新 更多