23

我知道智能指针用于资源管理并支持 RAII。

但是,在哪些极端情况下智能指针看起来并不聪明,并且在使用它时要记住的事情是什么?

4

10 回答 10

20

智能指针无助于防止图形结构中的循环。

例如,对象 A 持有指向对象 B 和对象 B 的智能指针 - 返回对象 A。如果在 A 与 B(或 B 与 A)断开连接之前释放指向 A 和 B 的所有指针,则 A 和 B 将相互保持并形成快乐的内存泄漏。

垃圾收集可以帮助解决这个问题 - 它可以看到两个对象都无法访问并释放它们。

于 2009-12-15T07:51:35.403 回答
10

我想提一下性能限制。智能指针通常使用原子操作(如Win32 API 中的InterlockedIncrement)进行引用计数。这些函数比普通整数算术要慢得多。

在大多数情况下,这种性能损失不是问题,只要确保不要对智能指针对象制作太多不必要的副本(最好在函数调用中通过引用传递智能指针)。

于 2009-12-15T08:05:22.377 回答
6

这很有趣:智能指针
这是 Andrei Alexandrescu 的“现代 C++ 设计”中的一个示例章节。

于 2009-12-15T07:52:48.377 回答
5

注意转换- 在原始指针和智能指针之间分配时。糟糕的智能指针 - 比如_com_ptr_t- 通过允许隐式转换使其变得更糟。大多数错误发生在过渡时。

注意循环- 如前所述,您需要弱指针来打破循环。但是,在复杂的图表中,这并不总是容易做到的。

选择太多- 大多数库提供具有不同优点/缺点的不同实现。不幸的是,大多数时候这些不同的变体是不兼容的,这成为混合库时的一个问题。(比如说,LibA 使用 LOKI,LibB 使用 boost)。必须提前计划很enable_shared_from_this糟糕,必须决定 和 之间的命名约定intrusive_ptrshared_ptr以及weak_ptr一堆对象很糟糕。


对我来说,shared_ptr(或类似功能之一)的最大优势在于它与创建时的销毁策略相耦合。C++ 和 Win32 都提供了很多摆脱事物的方法,这甚至都不好笑。在构建时进行耦合(不影响指针的实际类型)意味着我将两种策略都放在一个地方。

于 2009-12-15T10:28:58.317 回答
3

除了技术限制(已经提到:循环依赖),我想说关于智能指针最重要的事情是记住它仍然是删除堆分配对象的一种解决方法。在大多数情况下,堆栈分配是管理对象生命周期的最佳选择 - 以及引用的使用。

于 2009-12-15T07:58:53.560 回答
0

下面的文章是一篇非常有趣的论文

智能指针:不能和他们一起生活,不能没有他们

于 2009-12-15T07:50:11.813 回答
0

这里有几件事

  • 没有确定的实体会破坏该对象。通常希望准确地知道对象何时以及如何被销毁
  • 循环依赖——如果它们存在,你就会有内存泄漏。这通常weak_ptr是救援的地方。
于 2009-12-15T07:52:24.693 回答
0

Raymond Chen 对智能指针的矛盾是出了名的。关于析构函数何时实际运行存在问题(请注意,析构函数在明确定义的时间以明确定义的顺序运行;只是偶尔你会忘记它在函数的最后一行之后) .

还要记住,“智能指针”是一个相当大的类别。我包括std::vector在该类别中(astd::vector本质上是一个智能数组)。

于 2009-12-15T07:55:52.243 回答
0

在某些类型的具有循环的数据结构中,引用计数存在问题。从多个线程访问智能指针也可能会出现问题,对引用计数的并发访问可能会导致问题。boost 中有一个名为atomic.hpp的实用程序可以缓解这个问题。

于 2009-12-15T08:08:58.623 回答
0

许多人在使用与原始指针(指向相同对象)混合的智能指针时遇到问题。一个典型的例子是与使用原始指针的 API 交互时。
例如; 其中boost::shared_ptr有一个.get()返回原始指针的函数。如果小心使用,功能会很好,但很多人似乎会绊倒它。
恕我直言,这是“泄漏抽象”的一个例子。

于 2009-12-15T08:38:56.230 回答