带有对象或带有对象指针的C++容器

C++ container with object or with object pointer

本文关键字:对象 容器 C++ 指针      更新时间:2023-10-16

假设许多对象将被放入std::vector容器中,它们可以通过以下两种方式完成:

解决方案1

std::vector<MyObject> objArray;
for(int i=0; i<100; i++)
{
MyObject obj(i);
objArray.push_back(obj);
}

解决方案2

std::vector<boost::shared_ptr<MyObject> > objArray;
for(int i=0; i<100; i++)
{
MyObject *p_obj = new MyObject(i);
objArray.push_back(p_obj);
}

所以我的问题是:当我们从中选择一个解决方案时,是否有一些标准可以遵循?谢谢

在从中选择一个解决方案时,我们是否可以遵循一些标准?

默认情况下,您应该始终选择最简单、最直接的方式。在您的情况下,第一个是我所指的。如果您需要使用boost::shared_ptr进行动态分配,您就会知道。

通常,我会选择解决方案#1,即vector<MyObject>

这比#2(vector<shared_ptr<MyObject>>)更简单。

使用#1,您可以拥有良好的内存位置,因为MyObject实例按顺序存储在内存中,这对缓存非常友好(而且非常高效)
相反,在#2中,指针的值按顺序存储在向量中,但指向的对象分散在堆中,因此在这种情况下没有良好的局部性。

但是,一般规则也有例外。例如,如果MyObject的实例复制起来很重,移动起来又不便宜,我会使用vector<shared_ptr<MyObject>>选项。在这种情况下,指针语义可能会有所帮助。

无论如何,如果有疑问,请测量当您不确定某些代码的性能时,只需为您拥有的各种选项编写测试代码,并测量执行时间。

还要注意的是,如果使用C++11/14,您仍然可以使用指针语义,但使用的方式比shared_ptr更高效:事实上,您可以使用std::unique_ptrunique_ptr没有控制块(典型的shared_ptr),没有ref计数器的互锁递增和递减操作,并且通常比shared_ptr更快、更精简。如果您不需要共享所有权语义,并且可以使用C++11编译器,那么unique_ptrshared_ptr的一个很好的替代方案。

还要注意,如果为对象使用适当的分配器,则可以使vector<shared_ptr<...>>的效率略高:不要使用原始new,而是考虑使用make_shared。它有一些优点,比如在顺序内存位置中构建控制块和对象,因此与在远离受控对象的堆上创建的控制块相比,您具有更好的内存位置。

选择很简单:

  • 如果存储的对象不是多态的,则存储该对象
  • 如果对象是多态性的,并且在内部(包装器)处理多态性,则存储该对象
  • 否则,存储unique_ptr或shared_ptr是明智的

我避免最后一种情况(除非是实现细节)。