【问题标题】:Smart pointers in container like std::vector?容器中的智能指针,如 std::vector?
【发布时间】:2011-01-02 09:29:41
【问题描述】:

我正在学习智能指针 (std::auto_ptr) 并且刚刚阅读了 herehere 不应该将智能指针 (std::auto_ptr) 放入容器中(即 std::vector),因为即使大多数编译器也不会不要抱怨,这似乎是正确的。没有规则说智能指针不会在内部复制(例如通过vector 类)并转移其所有权,然后指针将变为NULL。到头来,一切都会搞砸。

实际上,这种情况多久发生一次?

有时我有指针向量,如果将来我决定想要一个智能指针向量,我的选择是什么?

我知道 C++0x 和 Boost 库,但现在,我更愿意坚持使用 STL 方法。

【问题讨论】:

  • std::tr1 (std::tr1::shared_ptr)中也有智能指针
  • 我不会真正将auto_ptr 称为智能指针 :) 这真的很愚蠢,因此(不幸的是)大多数关于智能指针的建议都不能应用于它(因为它的复制语义搞砸了)。

标签: c++ pointers std smart-pointers auto-ptr


【解决方案1】:

是的,您真的不能将std::auto_ptr 与标准容器一起使用。 std::auto_ptr 副本不等效,并且因为允许标准容器(和算法)随意复制它们的元素,所以这搞砸了。也就是说,复制std::auto_ptr 的操作具有其他的意义,而不仅仅是复制一个对象:它意味着转让所有权

您的选择是:

  1. 使用Boost Smart Pointers library。这可以说是您的最佳选择。
  2. 使用原始指针。只要您正确管理指针,这是快速且安全的。有时这可能很复杂或困难。例如,您必须自己处理(避免)双重删除问题。
  3. 使用您自己的引用计数智能指针。那太傻了;使用 Boost 智能指针。

【讨论】:

  • 别忘了 boost 的 ptr_vector 等等。
  • 如果你的编译器支持它,unique_ptr 也是一个选项。
  • 我强烈反对 shared_ptr 是最佳选择的想法。我认为它们是最后的选择,因为共享所有权会由于生命周期的不确定性带来很多问题:是的,只要你需要它,对象就会一直存在,但它也可能比这更久,特别是如果你不小心创建引用循环...
  • 我一直试图远离非 STL 的东西,直到我发现我想做的许多事情都可以通过 boost 库轻松解决。我一直在阅读有关 boost::shared_ptr 和 boost::weak_ptr 的内容,我发现它们非常有用,特别是因为 boost::shared_ptr 就像(在 Objective-C 中)拥有一个具有保留属性的属性,而 boost::weak_ptr 就像一个具有分配属性的属性。大多数 C++ 程序员可能不习惯的东西。事实上,如果不小心使用,它会产生循环。
  • @Matthieu @nacho4d 我更新了文本:使用来自 Boost 的智能指针之一。我认为该库涵盖了大多数最常见的情况,包括循环。但重要的是要留下“坚持 STL”的口头禅。很久以前我也去过这个营地,今天我认为它限制了你,它伤害你多于帮助你。我认为如果你有一个标准的 C++ 编译器而你没有 Boost,那么你的 C++ 开发环境是不完整的。比您自己的代码更信任 Boost,并且信任 Boost 就在那里。您的工作效率和代码质量将会蓬勃发展。
【解决方案2】:

您所指的问题涉及 auto_ptr,因为它将所有权转移到副本上。 shared_ptr 和 unique_ptr 与容器配合得很好。

【讨论】:

    【解决方案3】:

    与标准容器模板一起使用的任何类型都必须符合该容器的要求。特别是,该类型必须满足 CopyConstructibleAssignable 类型的要求。

    许多智能指针确实满足这些要求,并且可以与标准容器一起使用,但std::auto_ptr 不是其中之一,因为std::auto_ptr 的副本不等同于创建或分配它们的源。

    尽管在某些情况下标准容器的某些实现可能与 auto_ptr 一起使用,但依赖此类实现细节是危险的。

    【讨论】:

      【解决方案4】:

      理论上,如果您完全了解 STL 容器的内部实现并且不做任何可能失去 auto_ptr 所有权的事情,那么理论上您可以将 std::auto_ptr 与 STL 容器一起使用,但实际上使用带有原始 ptr 的容器要安全得多。

      “实际上,这种情况多久发生一次?” - 本身就是一个非常危险的问题。首先,STL——它不是一个单一的标准实现,有很多。每个都可以以不同的方式实现容器,因此您为避免所有“容器中的 auto_ptr”地雷而高度调整的代码可能会突然切换到另一个 STL 实现。此外,您的代码维护将非常复杂,任何看起来正确的代码更改都可能破坏您的程序。你怎么能记住或强迫其他维护者记住?在可能发生此类变化的任何地方发出警告?不可能。

      所以,结论:这只是一个坏主意,只会让人头疼

      【讨论】:

      • 理论上,在许多实际情况下,std::vector<std::auto_ptr<T> > 甚至无法编译。当标准禁止它时,任何理解都可以帮助你。
      • std::vector<:auto_ptr> > 在 VC9 中编译得很好,这不是符合标准的行为吗?
      【解决方案5】:

      对于具有 auto ptr 数据成员的类,我总是有一个返回新 auto ptr 的 clone 方法。然后,我实现了一个调用 clone 方法的赋值方法和复制构造函数(而不是 auto ptr 的默认赋值运算符)。这样您就可以安全地在 STL 容器中使用该类。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-03-04
        • 2022-01-23
        • 2019-07-09
        • 2014-07-06
        • 1970-01-01
        • 2011-06-14
        • 1970-01-01
        相关资源
        最近更新 更多