我应该存储整个对象,还是在容器中存储指向对象的指针?

从零开始设计一个新的系统。我将使用 STL 来存储某些长寿命对象的列表和映射。

问: 我应该确保我的对象具有拷贝构造函数并在 STL 容器中存储对象的拷贝,还是通常我自己管理生命周期和作用域并仅仅在 STL 容器中存储指向这些对象的指针更好?

我知道这有点缺乏细节,但是我正在寻找“理论上的”更好的答案,如果它存在的话,因为我知道这两种解决方案都是可能的。

玩指针游戏有两个非常明显的缺点: 1)我必须在 STL 之外的范围内自己管理这些对象的分配/释放。 2)我不能在堆栈上创建一个临时对象并将其添加到我的容器中。

我还漏掉了什么吗?

65702 次浏览

如果存储多态对象,则始终需要使用基类指针的集合。

也就是说,如果计划在集合中存储不同的派生类型,则必须存储指针,否则就会被切片守护进程吃掉。

你似乎很清楚其中的区别。如果对象很小并且容易复制,那么尽一切可能存储它们。

如果没有,我会考虑将智能指针(而不是 auto _ ptr,一种统计引用的智能指针)存储到您在堆上分配的智能指针中。显然,如果选择智能指针,则不能存储分配的临时堆栈对象(如前所述)。

@ Torbjörn关于切片的观点很有道理。

使用指针会更有效率,因为容器将只复制周围的指针,而不是复制完整的对象。

这里有一些关于 STL 容器和智能指针的有用信息:

为什么对标准容器使用 std: : auto _ ptr < > 是错误的?

为什么不两全其美呢: 做一个智能指针容器(如 boost::shared_ptrstd::shared_ptr)。您不必管理内存,也不必处理大型复制操作。

通常将对象直接存储在 STL 容器中是最好的,因为它最简单、最有效,并且最容易使用对象。

如果对象本身具有不可复制的语法或者是抽象基类型,则需要存储指针(最简单的方法是使用 share _ ptr)

因为人们对使用指针的效率表示赞同。

如果你正在考虑使用 std: : Vector,而且更新很少,并且你经常迭代你的集合,而且它是一个非多态类型,那么存储对象“ copy”将会更有效,因为你会得到更好的访问局部性。

奥托,如果更新是常见的存储指针将节省复制/重新安置成本。

这真的取决于你的情况。

如果对象很小,并且复制对象是轻量级的,那么在 stl 容器中存储数据就很简单,而且在我看来更容易管理,因为不必担心生存期管理。

如果对象很大,使用缺省构造函数没有意义,或者对象的副本很昂贵,那么使用指针存储可能是一种方法。

如果您决定使用指向对象的指针,请查看 提升指针容器库。这个提升库包装了所有的 STL 容器,以便与动态分配的对象一起使用。

每个指针容器(例如 ptr _ Vector)在将一个对象添加到容器时获得该对象的所有权,并为您管理这些对象的生命周期。还可以通过引用访问 ptr _ Container 中的所有元素。这样你就可以

class BigExpensive { ... }


// create a pointer vector
ptr_vector<BigExpensive> bigVector;
bigVector.push_back( new BigExpensive( "Lexus", 57700 ) );
bigVector.push_back( new BigExpensive( "House", 15000000 );


// get a reference to the first element
MyClass& expensiveItem = bigList[0];
expensiveItem.sell();

这些类包装了 STL 容器并可以使用所有的 STL 算法,这非常方便。

还有一些工具可以将容器中指针的所有权传递给调用方(通过大多数容器中的 release 函数)。

如果要在代码的其他地方引用这些对象,那么将它们存储在一个 ost: : share _ ptr 向量中。这样可以确保在调整向量大小时指向对象的指针仍然有效。

即:

std::vector<boost::shared_ptr<protocol> > protocols;
...
connection c(protocols[0].get()); // pointer to protocol stays valid even if resized

如果没有其他人存储指向对象的指针,或者列表没有增长和收缩,那么只需将其存储为普通的旧对象:

std::vector<protocol> protocols;
connection c(protocols[0]); // value-semantics, takes a copy of the protocol

很抱歉在事件发生三年之后突然出现,但是这里有一个警告..。

在我上一个大项目中,我的中央数据结构是一组相当简单的对象。项目进行了大约一年,随着需求的发展,我意识到对象实际上需要是多态的。经过几个星期的艰难和讨厌的脑部手术,才将数据结构修复为一组基类指针,并处理对象存储、强制转换等方面的所有附带损害。我花了几个月的时间来说服自己新的代码是有效的。顺便说一句,这让我认真思考 C + + 的对象模型设计得有多好。

在我当前的大项目中,我的中央数据结构是一组相当简单的对象。在项目实施一年后(恰好是今天) ,我意识到对象实际上需要是多态的。回到网上,找到了这个线程,找到了 Nick 到 Boost 指针容器库的链接。这正是我上次为了解决所有问题而不得不写的东西,所以这次我要试一试。

不管怎样,对我来说,这个道理是: 如果你的规格不是100% 固定的,那就去寻找指针,这样你可能会在以后为自己省下很多工作。

这个问题一直困扰着我。

我倾向于存储指针,但是我有一些额外的需求(SWIG lua wrappers)可能不适用于您。

这篇文章中最重要的一点是使用 你的目标你自己试试

我今天这样做是为了测试对1000万个对象的集合调用成员函数的速度,500次。

该函数根据 xdir 和 ydir (所有 float 成员变量)更新 x 和 y。

我使用 std: : list 来保存这两种类型的对象,我发现在 list 中存储对象比使用指针稍微快一些。另一方面,性能非常接近,所以这取决于如何在应用程序中使用它们。

作为参考,在我的硬件上使用 -O3时,指针需要41秒才能完成,原始对象需要30秒才能完成。