std :: map和'fat'值对象

时间:2009-12-26 10:08:53

标签: c++ performance

从性能的角度std::map<uint32_t, MyObject>std::map<uint32_t. MyObject*>,如果MyObject是'胖'(运算符=相当昂贵)并且我必须插入/更新/删除很多,那么什么更好?

6 个答案:

答案 0 :(得分:4)

如果您希望“按值”存储对象,但又不想执行昂贵的复制,那么根本不要进行复制。例如,您始终可以插入“空”对象(可以快速复制),然后在实际内容插入地图后填充它们。后者可以通过采用例如移动语义而不是复制语义以更有效的方式完成。关联容器不应该在已经插入的元素之间执行任何复制(虽然理论上它可能是可能的),所以一旦你处理了新的元素插入,你不应该遇到昂贵复制的任何其他问题。

例如,典型的“昂贵”插入方案可能如下所示

MyObject new_value(/* constructor arguments */);
// Maybe do some additional preparations on `new_value`
// ...

// And now: the actual insertion
map[key] = new_value;
// .. which makes a call to the heavy assignment operator

注意,在这种情况下,是谁正在调用赋值运算符。由于您可以控制实际复制,因此可以以更便宜的方式重写它,如下所示

MyObject& new_value = map[key];
// Now `new_value` is a reference to a default-constructed object

// Here you should "load" the `new_value` object with whatever information
// you want it to carry. That should cover both the original constructor's
// functionality from the previous piece of code, as well as any 
// post-constructor preparations
// ...

请注意,在第二种情况下,构建新值所需的工作量与第一种情况基本相同,但实际插入时没有额外的复制。另请注意,在这种情况下,您的对象必须是默认可构造的,这通常不是对标准容器元素强加的要求。

如果您决定“通过指针”存储对象,更好的办法是使用适当的智能指针而不是原始指针。

答案 1 :(得分:4)

检查Boost Pointer Container Library是否有安全保存指针的容器。

答案 2 :(得分:1)

std::map<uint32_t, boost::shared_ptr<MyObject> >是解决这个问题的好方法。

如果复制很昂贵,通常不希望按值存储地图值。

答案 3 :(得分:0)

如果复制MyObjects是一项昂贵的操作,那么性能会受到影响。但是,您应该自己对此进行基准测试,看看它是否是您应用所做的所有其他事情的背景下的问题。

如果你有提升,你应该考虑在你的地图中存储一个智能指针(可能是boost :: shared_pointer)而不是裸指针,因为这样更安全

答案 4 :(得分:0)

插入元素将实际调用复制构造函数,而不是operator =,并且您不应自动假设通过指针动态分配和访问对象的开销将比支付额外构造的价格更快。特别是对于C ++ 0x,rvalue引用可以使这个成本消失,并且将指针容器作为性能优化存储将会消失。

指出,不要假设在容器中存储胖对象是坏的,尤其是std :: map(它应该只制作一个副本)。额外的间接级别确实会对CPU绑定操作造成伤害。你应该衡量;但是存储指针的“线”通常比人们想象的要高得多。

这也取决于你的意思是昂贵的。现代处理器非常擅长移动内存。但是,如果昂贵你的意思是通过网络谈话或从磁盘读取,那么额外的副本可能是痛苦的(..同样,直到rvalue引用到来)。

答案 5 :(得分:-1)

插入对象会调用赋值运算符(=)。因此性能取决于MyObject的赋值运算符的实现。如果实现必须复制大量数据,则可能导致性能瓶颈。如果使用例如它不应该是一种写时复制方案。

我经常认为对象样式不是指针样式的性能。但是,如果它导致瓶颈取决于实际应用。

使用对象而不是指针的优点是使内存管理更容易。