【问题标题】:Smart pointers usage智能指针使用
【发布时间】:2010-12-29 12:20:54
【问题描述】:

我有一个项目,我希望更好地使用智能指针。

主要思想是在从函数返回新对象时使用它们。问题是使用什么智能指针? auto_ptrshared_ptr 来自 boost?据我所知,auto_ptr 速度较慢,但​​它可以回退到“纯”指针。

如果我在不需要的地方使用智能指针,会不会降低性能?

【问题讨论】:

  • 不要根据感知效率来选择智能指针(因为人类在感知效率方面绝对是糟糕透顶,而且正如所证明的那样,通常会出错)。选择演示您希望如何使用指针的智能指针。如果您正在转移所有权 auto_ptr 很好,如果您正在创建一个隐式共享对象,那么 shared_ptr 更好。

标签: c++ pointers boost smart-pointers


【解决方案1】:

是什么让您认为auto_ptrshared_ptr 慢?通常情况下,我希望反过来是正确的,因为shared_ptr 需要更新引用计数。

至于应该使用哪个,不同的智能指针意味着不同的所有权语义。所有权意味着在不再需要对象时删除该对象的责任。

  • 原始指针意味着没有所有权;正确使用智能指针的程序可能仍然在许多不打算拥有所有权的地方使用原始指针(例如,如果您需要将对对象的可选引用传递给函数,您通常会使用原始指针)。
  • scoped_ptr 表示单一(即非共享)、不可转让所有权。
  • auto_ptr 表示单一(即非共享)可转让所有权。这是我用来从函数返回一个新构造的对象的智能指针(该函数将对象传送给它的调用者)。 auto_ptr 的缺点是,由于定义 auto_ptr 时的语言限制,很难正确使用(这给它带来了非常糟糕的声誉,尽管智能指针的预期目的是具有单一、可转让的所有权语义曾经并且现在都是有效且有用的)。
  • unique_ptrauto_ptr 具有相同的语义,但使用新的 C++0x 特性(右值引用)使其比 auto_ptr 更安全(不易被错误使用)。如果你在一个有unique_ptr 可用的平台上开发,那么你应该使用它而不是auto_ptr
  • shared_ptr 表示共享所有权。在我看来,这被过度使用了。它确实有许多有效的用途,但它不应简单地用作默认选项。

我还要补充一点,shared_ptr 经常与 STL 容器一起使用,因为其他智能指针类在该上下文中无法实现其预期功能(由于在容器内部复制值)。这通常会导致使用shared_ptr,而共享所有权并不是真正的预期含义。在这些情况下,我建议(在可能的情况下)使用 boost 指针容器类(ptr_vectorptr_map 等),它们提供容器的(通常需要的)语义,具有可转移但单一(非共享) ) 所有权。

您应该始终考虑对象的所有权:在大多数情况下,通过干净的系统设计,每个对象都有一个明显的所有者,并且所有权不需要共享。这样做的好处是很容易准确地看到对象将在何时何地被释放,并且不需要引用计数开销。

[编辑以注明新的unique_ptr]

【讨论】:

  • 无论如何,shared_ptr 仍然有一些干净的场景很有用。我有一个线程框架,其中线程信息存储在 shared_ptr 中,一个副本提供给线程对象本身,并在线程结束时释放,另一个副本提供给调用者。这是确保线程结束后进行清理的最干净的方法,但允许调用者安全地跟踪线程的当前状态。
  • 可能“在大多数情况下,采用干净的系统设计”太强大了。真正的共享所有权情况并非那么罕见(尽管远不如单一所有权常见)。感谢您提供了一个很好的例子。
【解决方案2】:

您可能应该使用shared_ptr<>。如果不知道您到底想做什么,就很难更具体。最好阅读它的documentation,看看它是否满足您的需求。

性能差异很可能可以忽略不计。只有在极端情况下,我可能会产生明显的影响,例如每秒复制这些指针数百万次时。

【讨论】:

  • 性能差异不容忽视。由于 shared_ptr 的开销不仅仅是引用计数器的递增和递减。每个对象还有第二个新/删除维护信息!而且由于堆很慢,这在某些情况下可能很糟糕。此外,如果您有循环引用,shared_ptr 可能会导致内存泄漏(这可以通过使用weak_ptr 来解决;但您必须考虑更多!)。
  • @rstevens:您可以使用make_shared(),它只进行一次分配。无论如何,通常性能瓶颈不在使用的指针中,我怀疑 OP 的担忧是过早的优化。此外,无论您使用哪种智能指针或非智能指针,您都必须考虑内存泄漏。如果有的话,shared_ptr/weak_ptr 会更容易处理。
【解决方案3】:

我更喜欢shared_ptr,auto_ptr会带来很多麻烦,而且使用起来也不是很直观。如果你希望这个对象被插入到一个 STL 容器上,那么你当然要使用 shared_ptr。

提高性能是有代价的,但这是最小的,大部分时间你可以忽略它。

【讨论】:

  • 性能成本可能相当高!请务必在使用智能 ptrs 后进行分析,以查看影响是否可以接受。
【解决方案4】:

视情况而定。
共享指针比 auto_ptr 有更好的用途,后者具有改变分配所有权的不寻常特征。
auto_ptr 也不能在容器中使用。
如果您不想转让所有权,也不能使用 auto_ptr 作为返回值。
共享指针具有智能指针的所有优点,重载了相关的操作符以像指针一样工作,并且可以在容器中使用。 话虽如此,它们的使用并不便宜。
您必须分析您的需求,以确定您是否真的通过避免 shared_pointer 实现开销来获得一些东西

【讨论】:

  • 错误:auto_ptr 可以在容器中使用...因为它的原始特性...(容器中的使用是这些特性的原因!!!)
  • @rstevens:我不知道您的评论是什么意思。auto_ptr 不满足标准容器中元素的最基本要求之一。在复制或分配 auto_ptr 源和sink 不等价。因此auto_ptr 不应在标准容器中使用。
  • @user384706:auto_ptr 可用于标准容器,如 std::vector 和 std::list。它可能会导致其他容器出现问题,但由于 std::auto_ptr 和 std::-Containers 是一起开发的,所以它们保证可以一起工作。
  • @rstevens:auto_ptrs 的容器被禁止(根据标准委员会的要求)。试图使用它们的代码不应该编译。但是有 STL 实现(错误地)不拒绝这种情况。仅仅因为auto_ptrs 是标准库的一部分并不意味着它们可以与 stl 容器一起工作。大错特错!!
【解决方案5】:

仅使用 shared_ptr。使用 auto_ptr,您只能对您的对象有一个引用。 auto_ptr 也不慢,它必须比 shared_ptr 工作得更快。

为了不问这样的问题,你需要知道这个智能指针是如何工作的。

auto_ptr 只是存储指向您的对象的指针并在它的析构函数中销毁它。

auto_ptr 的问题在于,当您尝试复制它时,它会停止指向您的对象。

例如

auto_ptr a_ptr(new someClass);

auto_ptr another_ptr=aptr;// 这之后 another_ptr 指向你的类,但是 a_ptr 不再指向它了!

这就是我不建议你使用 auto_ptr 的原因。

共享指针计算有多少智能指针指向您的对象并在没有更多指针时销毁您的对象。这就是为什么你可以有超过 1 个指针指向你的对象。

但是共享指针也不是完美的。如果在你的程序中你有循环图(当你有类 A 和 B 和 A 有一个成员 shared_ptr 到 B 和 B 有或 B 的成员对象有 shared_ptr 指向 A)比 A 和 B 永远不会删除,你会有记忆力。

要使用 shared_ptr 编写正确的代码,您需要小心并使用weak_ptr。 更多信息请看这里http://www.boost.org/doc/libs/1_45_0/libs/smart_ptr/smart_ptr.htm

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-06
    • 1970-01-01
    • 1970-01-01
    • 2020-12-04
    • 2017-04-29
    • 1970-01-01
    • 2016-10-09
    • 1970-01-01
    相关资源
    最近更新 更多