将 unique_ptr 分配给引用时,析构函数在成员函数之前被调用

Destructor gets called before member function when assigning unique_ptr to a reference

我正在使用 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->operator()() 感觉更自然。谢谢。

因为当你这样做时

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

您创建的 std::unique_ptr 对象是 临时的 并且已被破坏,留下对不再存在的对象的引用,您进入了 undefined behavior.

当你这样做时

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

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

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 is a smart pointer that retains sole ownership of an object through a pointer and destroys that object when the unique_ptr goes out of scope.

std::unique_pointer<Sniffer> 是你的“1”中的一个临时变量,因此在语句完成后被销毁。它的析构函数在到达下一个语句 (h();) 之前销毁 Sniffer 对象。 h 是悬垂引用,因此 h()(即 h.operator()())的结果未定义。

在你的例子“2”中,对象 p 继续存在直到包含范围的末尾,即在语句 h();

之后

在此声明中

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

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

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

在此声明中

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

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

Sniffer& h = *p; 

在此范围内有效。