为什么实例化一个shared_ptr要调用destructor?

问题描述 投票:1回答:1

谁能解释一下为什么类的destructor要调用 bar 在同类型对象被初始化的行中被调用?

    #include <memory>
    #include <iostream>

    using namespace std;

    class bar
    {
      public:
        bar() {}

        ~bar() { std::cout << "destructor called " << std::endl; }
    };

    class foo
    {
      public:
        foo(std::shared_ptr<bar> barP) {}
    };


    int main() {

        std::shared_ptr<foo> f;
        std::cout << "before init " << std::endl;
        f = std::shared_ptr<foo>(new foo(std::shared_ptr<bar>(new bar())));
        std::cout << "after init"  << std::endl;
    }

输出。

before init 
destructor called 
after init
c++ c++11 shared-ptr smart-pointers
1个回答
4
投票

这句话。

f = std::shared_ptr<foo>(new foo(std::shared_ptr<bar>(new bar())));
                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

构建一个临时的 shared_ptr 在语句结束时超出了范围。 这时 shared_ptr 消失,带走 bar 的副本(因为没有 shared_ptr 活着)。)

但如果你改变 foo 读成这样。

class foo
{
  public:
    foo(std::shared_ptr<bar> barP) { m_bar = barP; }
    std::shared_ptr<bar> m_bar;
};

那么你得到的输出可能是你所期望的,因为... foo 保存一份《公约》的副本 shared_ptr 直到它(foo)超出了范围,并且该副本保持 bar 活着。

before init 
after init
destructor called

现场演示


1
投票

这是因为 bar 实例的生命力只与 foo 构造函数。 所以它被构造出来,传递到 shared_ptr,然后进入 foo 构造函数。 一旦该构造函数完成(即使是在同一行),表达式本身就完成了,所以 shared_ptr 完成,并销毁。

在结束时 main 前面 cout你还有一个 shared_ptr 归入 f但未命名的 shared_ptr 对你的 bar 对象已经 "超出范围 "了。


0
投票

首先,你不应该实例化的是 shared_ptr 这样一来 make_shared 来实例化 shared_ptr. 请检查修改后的代码 -

#include <memory>
#include <iostream>

using namespace std;

class bar
{
  public:
    bar() {}

    ~bar() { std::cout << "destructor called " << std::endl; }
};

class foo
{
  public:
    foo(std::shared_ptr<bar> barP) {}
};


int main() {

    std::shared_ptr<foo> f;
    std::cout << "before init " << std::endl;
    std::shared_ptr<bar> b = std::make_shared<bar>();
    f = std::make_shared<foo>(b);
    std::cout << "after init"  << std::endl;
}

上述程序的输出 -

before init 
after init
destructor called 

一般来说,你的代码发生的情况是,你通过了 new bar 的构造者。foo. 而且没有人持有所有权 bar 的共享指针,因此,ref计数变成了0,并且被删除了,因此被调用了destructor。所以,ref计数变成了0,它被删除了,因此被调用了destructor。

进一步阅读: make_shared vs new

© www.soinside.com 2019 - 2024. All rights reserved.