c++ - 智能指针 - std::shared_ptr用法




为什么C++库和框架从不使用智能指针? (6)

我在几篇文章中读到几乎永远不会使用原始指针。 相反,它们应该总是被包装在智能指针中,无论它是范围还是共享指针。

然而,我注意到像Qt,wxWidgets这样的框架和Boost这样的库永远不会返回也不期望智能指针,就好像它们根本没有使用它们一样。 相反,他们返回或期待原始指针。 这有什么理由吗? 当我编写公共API时,我应该远离智能指针吗?为什么?

只是想知道为什么当许多重大项目似乎避免使用智能指针时。


为了成为Java,Qt毫无意义地重新发明了标准库的许多部分。 我相信它现在确实有自己的智能指针,但总的来说,它几乎不是设计的顶峰。 就我所知,wxWidgets是在可用的智能指针写入之前就设计的。

至于Boost,我完全期望他们在适当的地方使用智能指针。 您可能必须更具体。

另外,不要忘记存在智能指针来强制所有权。 如果API没有所有权语义,那么为什么要使用智能指针呢?


你不应该远离智能指针,特别是在你需要传递对象的应用程序中使用它们。

图书馆往往只是返回一个值或填充一个对象。 他们通常没有需要在很多地方使用的对象,所以他们不需要使用智能指针(至少不需要在他们的界面中,他们可以在内部使用它们)。

我可以拿一个我们一直在研究的库为例,经过几个月的开发,我意识到我们只在几个类中使用了指针和智能指针(所有类的3-5%)。

在大多数地方通过引用传递变量已经足够,每当我们有一个可能为空的对象时,我们就会使用智能指针,而当我们使用的库迫使我们使用原始指针时。

编辑 (我无法评论,因为我的名声):通过引用传递变量非常灵活:如果你希望对象是只读的,你可以使用const引用(你仍然可以做一些令人讨厌的强制转换来编写对象),但您可以获得最大的保护(这与智能指针相同)。 但我确实同意返回对象更好。


好问题。 我不知道你提到的具体文章,但我不时读到类似的东西。 我的怀疑是这些文章的作者倾向于反对C ++风格的编程。 如果作者只在他必须的时候用C ++编程,然后尽快返回到Java或者他那样,那么他并不真正分享C ++的思维方式。

有人怀疑某些或大多数相同的作者更喜欢垃圾收集内存管理器。 我不这样做,但我认为与他们不同。

智能指针非常棒,但它们必须保持引用计数。 参考计数的保存需要花费 - 通常是适度的成本,但是在运行时仍然需要花费。 通过使用裸指针来保存这些成本没有问题,尤其是在指针由析构函数管理的情况下。

关于C ++的优秀之处之一是它支持嵌入式系统编程。 裸指针的使用是其中的一部分。

更新:一位评论者已经正确地观察到,C ++的新unique_ptr (自TR1以后可用)不计算引用。 评论者对“智能指针”的定义也不同于我的想法。 他对这个定义可能是正确的。

进一步更新:下面的评论线程是照亮。 所有这一切都是推荐阅读。


智能指针有两个问题(pre C ++ 11):

  • 非标准,所以每个图书馆都倾向于重塑自己(NIH综合症和依赖性问题)
  • 潜在成本

缺省智能指针是免费的,它是unique_ptr 。 不幸的是,它需要C ++ 11移动语义,这只是最近才出现的。 所有其他智能指针都具有成本( shared_ptrintrusive_ptr )或者具有比理想语义( auto_ptr )更少的成本。

随着C ++ 11的发展,引入一个std::unique_ptr ,人们会想到它终于结束了......我不那么乐观。

只有少数几个主要的编译器实现了大多数C ++ 11,并且仅在其最新版本中实现。 我们可以预期,像QT和Boost这样的主流图书馆愿意保持与C ++ 03的兼容性,这有时会阻碍广泛采用新的闪亮的智能指针。


这也取决于你在哪个领域工作。我写游戏引擎为生,我们避免像瘟疫一样的提升,在游戏中,提升的开销是不可接受的。 在我们的核心引擎中,我们最终编写了自己的stl版本(就像ea stl一样)。

如果我要写一个表单应用程序,我可能会考虑使用智能指针; 但是一旦内存管理是第二性的,没有对内存进行粒度控制就变得安静烦人。


除了许多库是在标准智能指针出现之前编写的,最大的原因可能是缺少标准的C ++应用程序二进制接口(ABI)。

如果你正在编写一个只有头文件的库,你可以将智能指针和标准容器传递给你的内容。 它们的源代码在编译时可用于您的库,因此您只依赖其接口的稳定性,而不依赖于它们的实现。

但是由于缺乏标准的ABI,您通常无法跨模块边界安全地传递这些对象。 GCC shared_ptr可能与MSVC shared_ptr不同,后者也可能与Intel shared_ptr不同。 即使使用相同的编译器,这些类也不保证在版本之间是二进制兼容的。

底线是,如果你想分发你的库的预建版本,你需要一个标准的ABI来依靠它。 C没有一个,但编译器供应商对于给定平台的C库之间的互操作性非常好 - 事实上有标准。

这种情况对于C ++来说并不是那么好。 各个编译器可以处理它们自己的二进制文件之间的互操作,因此您可以选择为每个受支持的编译器(通常是GCC和MSVC)分发一个版本。 但是鉴于此,大多数库只是导出一个C接口 - 这意味着生鱼的指针。

但是,非库代码通常更喜欢智能指针而非原始指针。





smart-pointers