我需要在自己的析构函数中手动重置shared_ptr吗?

5

假设我有一个类如下所示:

class A {
public: // I know, I know...
    shared_ptr<string> aString;
};

我需要像这样拥有一个析构函数吗?

~A() {
    aString.reset();
}

为了确保所有权正确释放,我进行了一些测试,似乎不需要这样做。即当A的实例超出作用域或被删除(如果我通过shared_ptr引用它,则重置),字符串也会被删除(我使用一个更复杂的示例来确认这一点)。然而,这可能与我所使用的编译器(clang-700.0.72)有关。我的问题是:这总是这种情况吗?还是最好像删除任何其他空指针一样明确重置这些实例?

在复制构造函数和赋值函数中,您应该考虑需要什么。默认情况下,将得到一个指向相同对象的第二个共享指针,并带有增加的共享计数(浅拷贝)。如果您需要深度拷贝,则必须自行进行安排。(这很不寻常,因为shared_ptr的整个意义在于共享,而深度拷贝意味着没有共享)。 - MSalters
是的,如果我需要共享所有权 - 无论是短期还是长期 - 我会期望将所有使用计数增加一。在引发我问题的特定情况中,我有一个类,很可能只会有一个所有者,但需要强烈保持对该成员的控制 - 这也意味着在我的实际情况中指针永远不会在类外部使用,即使它确实被使用,也至少会对意外删除进行+1操作(我知道这种情况发生的可能性很小,因为这不是库代码 :) - Morpheu5
在这种情况下,你不是最好使用std::unique_ptr并分发引用吗?如果有人要对引用调用delete,我相信你有权进行Linus Torvalds模仿。 - MSalters
我确实可以这样做。我的大脑正在激烈地辩论,我是想走安全路线,还是未来需要以不舒适的高速率举起几根手指 :) - Morpheu5
1
当你的同行删除引用时,你应该更多地考虑“截肢”而不是举手之劳。这样可以减少伤害 ;) - MSalters
3个回答

8
不需要这样做。作为正常析构函数的一部分,类的每个成员都将依次被销毁。智能指针的析构函数将处理必要的记账工作,在这种情况下是隐式的reset操作。

7
不,这就是智能指针的主要目的:自动管理内存。shared_ptr 的析构函数会自动减少引用计数,如果引用计数达到零,将调用删除器。如果不提供析构函数,则会生成一个默认析构函数:

§ 12.4.4 如果一个类没有用户声明的析构函数,则会隐式声明一个析构函数为 defaulted。

类的销毁将保证成员的销毁:

§ 12.4.8 在执行析构函数体并销毁其中分配的任何自动对象之后,类 X 的析构函数调用直接非变量、非静态数据成员的析构函数(...)

对于 shared_ptr,这意味着:

§ 20.8.2.2.2.1

~shared_ptr();

作用:

  • 如果 *this 为空或与另一个 shared_ptr 实例共享所有权(use_count() > 1),则没有副作用。

  • 否则,如果 *this 拥有对象 p 和删除器 d,则调用 d(p)。

  • 否则,*this 拥有指针 p,并调用 delete p。

这种行为被很好地总结为零规则


3
在 StackOverflow 上,是否接受以称呼某人的方式并编辑你的帖子以包括他们的观点? - donkopotamus
1
@Morpheu5,我已经添加了默认析构函数行为的标准引用。 - Bartek Banachewicz
1
@LightnessRacesinOrbit:如果抛出异常,ctor确实会调用成员析构函数;)说真的,如果你正在解决构建问题并且无法弄清楚为什么需要从ctor调用那些成员dtor,这可能会让人感到困惑。 - MSalters
1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Bartek Banachewicz
@BartekBanachewicz:我接受你的道歉。祝你拥有愉快的一天! - Lightness Races in Orbit
显示剩余3条评论

3

不会出现这种情况,这是明确的,我所知道的没有编译器错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接