smart_ptr属于类segfault的属性

时间:2016-05-25 11:38:43

标签: c++ c++11 segmentation-fault smart-pointers

我想知道这个例子是否会导致段错误,因为对象的dtor被调用,我仍然将shared_ptr保存到对象的属性。

struct foo{
    std::shared_ptr<std::string> const bar = std::make_shared<std::string>("foo");

    foo() {std::cout << "CTOR!" << std::endl;} 

    ~foo(){std::cout << "DTOR!" << std::endl;}
};
int main() {
    std::shared_ptr<std::string> ptr;
    {
        std::shared_ptr<foo> foo_ptr = std::make_shared<foo>();
        ptr = foo_ptr->bar;
    }
    std::cout << *ptr << std::endl;


    return 0;
}

2 个答案:

答案 0 :(得分:4)

不,它赢了。通过将std::shared_ptr分配给另一个人,你就是在宣称它不会死亡。

此操作ptr = foo_ptr->bar;会将共享指针的计数器增加一。这将保证免费商店中动态分配的对象仍然存活。

即使对于被破坏对象的属性也是如此?!

是的,这是真的。在非正式的谈话中,动态分配内存的一个用途是当你希望你的对象比它的所有者(另一个对象,指针......)更多地生存时。因此,在容器对象死亡后,该对象将完好无损。

尝试执行此代码。它会让你清楚:

std::shared_ptr<std::string> ptr;
{
    std::shared_ptr<foo> foo_ptr = std::make_shared<foo>();
    std::cout <<"References Count:" << foo_ptr->bar.use_count()<<"\n";
    ptr = foo_ptr->bar;
    std::cout <<"References Count:" << foo_ptr->bar.use_count()<<"\n";
}
std::cout <<"References Count:" << ptr.use_count()<<"\n";
std::cout << *ptr << std::endl;

将输出:

CTOR!
References Count:1
References Count:2
DTOR!
References Count:1
foo

Online Demo

答案 1 :(得分:4)

这里没有问题。 std::shared_ptr旨在实现这一目标。如果我们看看代码是如何工作的,你可以看到

std::shared_ptr<std::string> ptr;

创建一个名为shared_ptr的{​​{1}},指向任何内容。

ptr

现在我们创建名为{ std::shared_ptr<foo> foo_ptr = std::make_shared<foo>(); ptr = foo_ptr->bar; } 的{​​{1}},指向shared_ptr的有效实例,foo_ptr构造函数初始化foo。然后,我们将foo分配给bar。当我们这样做时,bar的内部引用计数器增加1(到2),现在ptrbar 共享内部指针。然后我们到达范围的末尾并且bar被销毁,当它被破坏时,它调用ptr的析构函数来调用foo_ptr的析构函数。当foo被销毁时,它会放弃对指针的访问权限。这意味着它减少了参考计数器。如果它是最后一个bar(当输入析构函数时计数器为1),那么指针也会被删除,如果不是,那么它什么也不做。由于计数器不止一个(由于bar而为2),因此指针不会被删除,而是由于所有权为共享而保留在shared_ptr中。 / p>

ptr = foo_ptr->bar

此处ptr仍然有效,因为它共享所有权,因此没有问题。当程序结束时,我们输入std::cout << *ptr << std::endl; 的析构函数并看到引用计数器位于1,因此指针被删除,从而确保我们没有内存泄漏。因此ptr不仅可以安全地复制指针,还可以自动进行内存管理。这确实带来了一些额外的成本。有一个原子参考计数器可以使用,所以它不像原始指针那么小或快,但它更安全。