【问题标题】:Pointer to vector vs vector of pointers vs pointer to vector of pointers指向向量的指针与指针向量与指向指针向量的指针
【发布时间】:2011-08-04 15:50:12
【问题描述】:

只是想知道您认为关于 C++ 中向量的最佳实践是什么。

如果我有一个包含向量成员变量的类。 这个向量什么时候应该被声明为:

  1. “整个对象”向量成员变量包含值,即vector<MyClass> my_vector;
  2. 指向向量的指针,即vector<MyClass>* my_vector;
  3. 指针向量,即vector<MyClass*> my_vector;
  4. 指向指针向量的指针,即vector<MyClass*>* my_vector;

我的一个类中有一个特定示例,我目前已将向量声明为案例 4,即vector<AnotherClass*>* my_vector; 其中 AnotherClass 是我创建的另一个类。

然后,在我的构造函数的初始化列表中,我使用 new 创建向量:

MyClass::MyClass()
: my_vector(new vector<AnotherClass*>())
{}

在我的析构函数中,我执行以下操作:

MyClass::~MyClass()
{
  for (int i=my_vector->size(); i>0; i--)
  {
    delete my_vector->at(i-1);
  }
  delete my_vector;
}

向量的元素被添加到我的类的方法之一中。 我不知道有多少对象会提前添加到我的向量中。这是在代码执行时根据解析 xml 文件决定的。

这是好的做法吗?还是应该将向量声明为其他情况 1、2 或 3 之一?

什么时候用哪种情况?

如果向量的元素是另一个类的子类(多态性),我知道它们应该是指针。但是在其他情况下是否应该使用指针?

非常感谢!!

【问题讨论】:

    标签: c++ pointers vector


    【解决方案1】:

    通常解决方案 1 是您想要的,因为它是 C++ 中最简单的:您不必管理内存,C++ 会为您完成所有工作(例如,您不需要提供任何析构函数) .

    在某些特定情况下这不起作用(尤其是在处理多态对象时),但总的来说这是唯一的好方法。

    即使在使用多态对象或需要堆分配对象(无论出于何种原因)时,原始指针也几乎从来没有是一个好主意。相反,使用智能指针或智能指针容器。现代 C++ 编译器提供来自即将到来的 C++ 标准的shared_ptr。如果你使用的编译器还没有这个功能,你可以使用implementation from Boost

    【讨论】:

    • 我想知道为什么人们在这种情况下从不提及Boost.Pointer ContainerBoost.Reference
    • @Space 我有,有点像:“使用智能指针或智能指针容器。”不过我从来没有使用过它们,所以我不太有信心谈论它们的好处。
    • @Konrad:“......原始指针(在容器内)几乎从来都不是一个好主意”。只是好奇-除了在容器中使用原始指针的(手动)内存管理方面之外,还有其他原因不在容器中使用原始指针吗?我模糊地记得有一个原因:“作为容器(比如向量),增长/收缩它们可能会分配/取消分配/复制/移动它们的内容,如果它们的内容是原始指针,这可能会导致问题/不良副作用对象而不是对象的 shared_ptr。”这是准确/正确的吗?
    • @decimus 这还不够理由吗?我不认为你提到的原因是完全准确的。指针本身可以毫无问题地复制和移动。只有当对象需要管理这些指针时,这才会变得棘手,因为那时您需要提供适当的复制和赋值语义。
    • for example you wouldn’t need to provide any destructor then 对吗?向量本身不会被删除,在这种情况下您将有内存泄漏。你仍然应该创建一个析构函数并说delete theVector
    【解决方案2】:

    绝对是第一!

    您使用 vector 进行自动内存管理。使用指向向量的原始指针意味着您不再获得自动内存管理,这没有意义。

    至于值类型:所有容器基本上都假定类值语义。同样,在使用指针时您必须进行内存管理,而 vector 的目的就是为您做这件事。这也在书C++ Coding Standards 的第79 项中进行了描述。如果您需要使用共享所有权或“弱”链接,请改用适当的智能指针。

    【讨论】:

      【解决方案3】:

      手动删除向量中的所有元素是一种反模式,违反了 C++ 中的 RAII 习惯用法。因此,如果您必须在vector 中存储指向对象的指针,最好使用“智能指针”(例如boost::shared_ptr)来促进资源破坏。 boost::shared_ptr 例如在对对象的最后一个引用被销毁时自动调用delete

      也无需使用new 分配MyClass::my_vector。一个简单的解决方案是:

      class MyClass {
      
         std::vector<whatever> m_vector;
      };
      

      假设whatever 是智能指针类型,则没有额外的工作要做。就是这样,当MyClass 实例的生命周期结束时,所有资源都会自动销毁。

      在许多情况下,您甚至可以使用普通的std::vector&lt;MyClass&gt; - 这就是向量中的对象可以安全复制的时候。

      【讨论】:

      • 当您说“手动删除向量中的所有元素”时,您的意思是 not 在析构函数中吗?来自 wikipedialink “.. 并随着相同对象的销毁而发布,即使在出现错误的情况下也能保证发生。”这是否意味着如果您删除带有析构函数的向量中的元素,那么您就没有违反 RAII?
      【解决方案4】:

      在您的示例中,向量在创建对象时创建,并在对象被销毁时被销毁。这正是使vector 成为该类的普通成员时的行为。

      此外,在您当前的方法中,您在复制对象时会遇到问题。默认情况下,指针将生成平面副本,这意味着对象的所有副本将共享相同的向量。这就是为什么,如果你手动管理资源,你通常需要The Big Three

      指针向量在多态对象的情况下很有用,但您应该考虑其他替代方法:

      1. 如果向量拥有对象(这意味着它们的生命周期受限于向量的生命周期),您可以使用boost::ptr_vector
      2. 如果对象不属于向量,您可以使用boost::shared_ptr 向量或boost::ref 向量。

      【讨论】:

        【解决方案5】:

        指向 vector 的指针很少有用 - vector 的构造和销毁成本很低。

        对于vector 中的元素,没有正确答案。 vector 多久更改一次?复制构造vector 中的元素需要多少成本?其他容器是否有对vector 元素的引用或指针?

        根据经验,在您看到衡量复制您的课程非常昂贵之前,我不会给出任何指示。当然,您提到的将基类的各种子类存储在vector 中的情况将需要指针。

        如果您的设计要求您将指针用作 vector 元素,那么像 boost::shared_ptr 这样的引用计数智能指针可能是最佳选择。

        【讨论】:

        • 所以在我的例子中,如果 AnotherClass 是一个有很多成员变量的大类,那么将这些元素作为指针存储在向量中可能是个好主意?避免复制大对象。
        • @Lisa:没错。正确答案只能是“取决于”。
        • 您能否详细说明第一点——“指向向量的指针很少有用——向量的构造和破坏都很便宜。”怎么样?
        【解决方案6】:

        复杂的答案:视情况而定。

        如果您的向量是共享的或具有与嵌入它的类不同的生命周期,则最好将其保留为指针。 如果您引用的对象没有(或有昂贵的)复制构造函数,那么最好保留一个指针向量。相反,如果您的对象使用浅拷贝,则使用对象向量可以防止您泄漏...

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-09-10
          • 1970-01-01
          • 2013-07-19
          • 2020-04-13
          • 2018-08-28
          相关资源
          最近更新 更多