聪明的指针--为什么要使用它们,应该使用哪种?

2022-08-26 00:00:00 c++ smart-pointers

一般问题
现在我读了很多关于智能指针的文章,在很多情况下,共享指针似乎是"完美的"。然而,我也读到了周期性引用或类似的东西?哪里不能使用shared_ptr?我很难理解这一点,有谁能举一个简单的例子来说明这一点吗?

我真的想知道,弱_ptr提供了什么普通指针不能提供的?-因为它们不增加引用计数,所以它们不能保证它们所指向的内存仍然有效?

我的个人项目:
在一个项目中,我有两个"全局"容器(这两个容器很快都会移动到一个类中),它们都填充了"对象"。然而,两者都应该"指向"相同的对象。对象不能存在于这些容器之外,而且不可能一个容器包含该对象,而另一个容器不包含该对象。

目前我只是简单地使用普通指针来管理内存,并且有一个createObject&;destroyObject方法来管理内存。

这个设计好吗?我是否应该使用智能指针?


解决方案

回答您的各种问题:

循环引用是指两个不同的对象各自具有指向另一个对象的Shared_PTR。

例如:

struct Foo {
     shared_ptr< Bar > m_bar;
};

struct Bar {
     shared_ptr< Foo > m_foo;
};


void createObject()
{
    shared_ptr< Foo > foo( new Foo );
    shared_ptr< Bar > bar( new Bar );
    foo->m_bar = bar;
    bar->m_foo = foo;
    //Neither of these objects will be released here
}

这可能会导致两个对象都不会被释放,因为foo将始终将对bar的引用计数保持在1以上,而foo将不会被释放,因为bar将始终将其引用计数保持在1以上。

这是一种可以使用WARNCE_PTR克服的情况,因为它们不会增加引用计数。正如您所指出的,这不会阻止释放PTR,但确实允许您在使用对象之前检查对象是否仍然存在,这是使用标准指针所做不到的。

对于您提供的示例,您几乎应该始终使用智能指针而不是原始指针,因为它们允许对象在超出作用域时自动释放,而不是您必须确保它是自己完成的,这很容易出错。在您有异常的情况下尤其如此,它可以很容易地跳过您编写的任何发布代码。

例如,以下代码可能会导致问题:

Foo* foo = createObject();
foo.doSomething();
deleteObject( foo );

如果foo.doSomething为Except,则将永远不会调用DeleteObject,并且Foo将不会被释放。

但是,这将是安全的:

shared_ptr< Foo > foo = createObject();
foo.doSomething();

无论是否发生异常,Shared_ptr都将在代码块末尾自动释放。

这里很好地讨论了指针和智能指针:Pointers, smart pointers or shared pointers?

相关文章