我应该存储整个对象还是指向容器中的对象的指针?
从头开始devise一个新的系统。 我将使用STL来存储特定的长寿命对象的列表和地图。
问题:我应该确保我的对象有复制构造函数,并将对象的副本存储在我的STL容器中,还是自己pipe理生命期和范围通常更好一些,只是将指向这些对象的指针存储在我的STL容器中?
我意识到这在细节方面有些短暂,但是如果存在,我正在寻找“理论”更好的答案,因为我知道这两种解决scheme都是可能的。
玩指针的两个非常明显的缺点:1)我必须在STL之外的范围内自己pipe理这些对象的分配/释放。 2)我不能在堆栈上创build一个临时对象并将其添加到我的容器中。
还有什么我失踪?
由于人们正在争取使用指针的效率。
如果你正在考虑使用一个std :: vector,如果更新很less,而且你经常迭代你的集合,并且它是一个非多态types的存储对象“副本”将更加有效,因为你将获得更好的引用位置。
Otoh,如果更新是通用的存储指针将节省复制/重定位成本。
这真的取决于你的情况。
如果你的对象很小,并且做一个对象的拷贝是轻量级的,那么把数据存储在一个stl容器中是直截了当的,而且在我看来更容易pipe理,因为你不必担心生命周期pipe理。
如果对象很大,并且有一个默认的构造函数没有意义,或者对象的副本很昂贵,那么使用指针进行存储可能是一种方法。
如果您决定使用指向对象的指针,请查看Boost指针容器库 。 这个boost库封装了所有的STL容器,用于dynamic分配的对象。
每个指针容器(例如ptr_vector)在将对象添加到容器时拥有对象的所有权,并为您pipe理这些对象的生命周期。 您还可以通过引用访问ptr_容器中的所有元素。 这可以让你做一些事情
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容器,并使用所有STLalgorithm,这非常方便。
还有一些设备可以将容器中的指针的所有权转移给调用者(通过大多数容器的释放function)。
如果要存储polymporhic对象,则始终需要使用基类指针的集合。
这就是说,如果你计划在你的集合中存储不同的派生types,你必须存储指针或被切片deamon吃掉。
对不起,在事件发生后的三年,但在这里警示说明…
在我最后一个大项目中,我的中心数据结构是一套相当直接的对象。 在项目进行一年左右,随着需求的发展,我意识到对象实际上需要是多态的。 经过几个星期的困难和讨厌的脑部手术才将数据结构固定为一组基类指针,并处理对象存储,铸造等所有的附带损伤。 我花了几个月的时间来说服自己,新的代码工作。 顺便说一句,这让我很难想象如何devise精良的C ++对象模型。
在我目前的大项目中,我的中心数据结构是一组相当简单的对象。 在项目(大概是今天)大概一年的时候,我意识到对象实际上需要是多态的。 回到networking,发现这个线程,并发现尼克的链接到Boost指针容器库。 这正是我上次写的解决所有问题的方法,所以这次我会放手一下。
无论如何,对于我来说,道德,如果你的规范不是百分之百地投入到石头上去的话,那么你可能会在以后为自己节省大量的工作。
为什么不能得到两全其美的方法:做一个智能指针的容器(比如boost::shared_ptr
或者std::shared_ptr
)。 您不必pipe理内存,也不必处理大型复制操作。
通常将对象直接存储在STL容器中是最好的,因为它是最简单,最有效的,并且最容易使用该对象。
如果你的对象本身具有不可复制的语法,或者是一个抽象的基types,你将需要存储指针(最简单的就是使用shared_ptr)
你似乎对这个区别有很好的把握。 如果物体很小,容易复制,那么一定要把它们存储起来。
如果没有,我会考虑将智能指针(不是auto_ptr,ref计数智能指针)存储到您在堆上分配的指针。 显然,如果你select智能指针,那么你不能存储临时堆栈分配的对象(如你所说)。
@ Torbjörn关于切片很好。
使用指针会更有效,因为容器只会复制指针而不是完整的对象。
这里有一些关于STL容器和智能指针的有用信息:
为什么在标准容器中使用std :: auto_ptr <>是错误的?
如果对象被引用到代码中的其他地方,则存储在boost :: shared_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
这个问题一直在困扰着我。
我倾向于存储指针,但我有一些额外的要求(SWIG lua包装),可能不适用于你。
这篇文章中最重要的一点就是使用你的对象 自己testing它
我今天做了这个testing,在500万次的1000万个对象集合上调用成员函数的速度。
该函数根据xdir和ydir(所有浮点成员variables)更新x和y。
我使用std :: list来保存这两种types的对象,我发现将对象存储在列表中比使用指针要快一些。 另一方面,performance是非常接近的,所以这取决于他们将如何在你的应用程序中使用。
作为参考,在我的硬件上使用-O3指针需要41秒才能完成,原始对象需要30秒才能完成。