指向vector的指针vs指向vector的指针vs指向vector的指针

Pointer to vector vs vector of pointers vs pointer to vector of pointers

本文关键字:指针 指向 vector vs      更新时间:2023-10-16

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

如果有一个包含vector成员变量的类。什么时候声明这个向量a:

  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创建vector:
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文件决定的。

这是好的做法吗?还是应该将vector声明为其他情形1、2或3中的一种?

何时使用哪个case?

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

非常感谢!

通常解决方案1是你想要的,因为它是c++中最简单的:你不需要管理内存,c++为你做了所有这些(例如,你不需要提供任何析构函数)。

在特定的情况下,这不起作用(最明显的是在处理多态对象时),但通常这是唯一的好方法。

即使在处理多态对象或需要堆分配对象时(无论出于何种原因),原始指针几乎都不是一个好主意。相反,使用智能指针或智能指针的容器。现代c++编译器从即将发布的c++标准中提供shared_ptr。如果您使用的编译器还没有这个功能,那么您可以使用Boost中的实现。

绝对是第一!

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

关于值类型:所有容器基本上都采用类值语义。同样,当你使用指针时,你需要做内存管理,而vector的目的就是为你做这些。这在《c++编码标准》一书的第79项中也有描述。如果您需要使用共享所有权或"弱"链接,请使用适当的智能指针。

手动删除vector中的所有元素是一种反模式,并且违反了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<MyClass>——这是在vector中的对象可以安全复制的情况下。

在您的示例中,vector在创建对象时创建,在对象销毁时销毁。这正是使vector成为类的普通成员时所得到的行为。

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

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

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

指向vector的指针很少有用——vector的构造和销毁都很便宜。

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

根据经验,在您看到测量您的类的复制是昂贵的之前,我不会使用指针。当然,您提到的在vector中存储基类的各种子类的情况将需要指针。 如果您的设计要求您使用指针作为vector元素,那么像boost::shared_ptr这样的引用计数智能指针可能是最佳选择。

复杂的答案:看情况。

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