有一个众所周知的图像(备忘单),称为“ C ++容器选择”。这是为所需用途选择最佳容器的流程图。
有人知道它是否已经有C ++ 11版本吗?
这是上一个:
有一个众所周知的图像(备忘单),称为“ C ++容器选择”。这是为所需用途选择最佳容器的流程图。
有人知道它是否已经有C ++ 11版本吗?
这是上一个:
Answers:
我所不知道的,但是我想可以从文字上做。此外,图表略有偏离,因为list
通常来说容器并不是一个很好的容器,也不是forward_list
。这两个列表都是针对利基应用的非常专业的容器。
要构建这样的图表,您只需要两个简单的准则:
首先,通常不必担心性能。仅当您开始处理数千个(或更多)项目时,才会真正考虑到O的大问题。
容器有两大类:
find
操作然后你就可以在它们上面建几个适配器:stack
,queue
,priority_queue
。我将把适配器放在这里,它们足够专业,可以识别。
问题1:联想?
问题1.1:订购了吗?
unordered_
容器,否则请使用其传统的有序命令。问题1.2:分隔键?
map
,否则请使用set
问题1.3:重复吗?
multi
,否则不要使用。例:
假设我有几个具有唯一ID的人,并且我想尽可能简单地从其ID中检索人数据。
我想要一个find
功能,因此需要一个关联容器
1.1。我不在乎订单,因此是一个unordered_
容器
1.2。我的密钥(ID)与其关联的值是分开的,因此map
1.3。该ID是唯一的,因此不能重复输入。
最终答案是:std::unordered_map<ID, PersonData>
。
问题2:内存稳定吗?
list
问题2.1:哪个?
list
; a forward_list
仅对减少内存占用量有用。问题3:动态尺寸?
{ ... }
语法),则可以使用array
。它取代了传统的C阵列,但具有便捷的功能。问题4:双端?
deque
,否则使用vector
。您会注意到,默认情况下,除非需要关联容器,否则您的选择将是vector
。事实证明,这也是Sutter和Stroustrup的推荐。
array
不需要默认的可构造类型;2)选择multi
s并不是说允许重复,而是更多关于是否保留它们很重要(您可以将重复项放入非multi
容器中,恰好只有一个保留)。
map.find(key)
比起可口性要好得多std::find(map.begin(), map.end(), [&](decltype(map.front()) p) { return p.first < key; }));
,因此从语义上讲,这find
是一个成员函数,而不是来自的成员函数很重要<algorithm>
。至于O(1)vs O(log n),它不影响语义;我将从示例中删除“有效”,然后将其替换为“轻松”。
deque
也具有此属性?
deque
,元素只有在任一端按下/弹出时才稳定;如果您开始在中间插入/删除,则最多将洗净N / 2个元素以填充所创建的间隙。
我喜欢Matthieu的回答,但是我将重新声明流程图,如下所示:
默认情况下,如果您需要一个容器,请使用std::vector
。因此,仅通过提供替代的某些功能来证明每个其他容器都是合理的std::vector
。
std::vector
要求它的内容是可移动构造的,因为它需要能够随机播放周围的项目。这对内容来说并不是一个沉重的负担(请注意,由于等等,不需要默认的构造函数emplace
)。但是,大多数其他容器不需要任何特定的构造函数(再次感谢emplace
)。因此,如果您有一个绝对不能实现 move构造函数的对象,那么您将不得不选择其他东西。
A std::deque
是具有的许多属性的常规替换,std::vector
但是您只能在双端队列的两端插入。中间的插入物需要移动。一个std::list
放在它的内容没有要求。
std::vector<bool>
不是。好吧,这是标准的。但这不是vector
通常意义上的,因为std::vector
通常会允许进行禁止的操作。并且最肯定不包含bool
s。
因此,如果您需要vector
包含的容器的真实行为,则bool
不会从中获取它std::vector<bool>
。因此,您必须使用std::deque<bool>
。
如果您需要在容器中查找元素,并且搜索标签不能只是索引,那么您可能需要放弃std::vector
使用set
和map
。注意关键字“ 可能 ”;一个排序std::vector
有时是合理的替代方案。或Boost.Container's flat_set/map
,它实现了sorted std::vector
。
现在有四种变体,每种都有自己的需求。
map
当搜索标签与您要查找的项目不同时,请使用a 。否则请使用set
。unordered
时,你有很多在集装箱中的物品和搜索性能绝对必须O(1)
的,而不是O(logn)
。multi
,如果您需要多个项目具有相同的搜索标签。如果需要始终根据特定比较操作对项目容器进行排序,则可以使用set
。或者,multi_set
如果您需要多个项目具有相同的值。
或者,您可以使用sorted std::vector
,但是必须保持其排序。
当迭代器和引用无效时,有时会引起关注。如果您需要一个项目列表,以便在其他各个地方都具有这些项目的迭代器/指针,则std::vector
无效的方法可能不合适。任何插入操作都可能导致无效,具体取决于当前的大小和容量。
std::list
提供了有力的保证:迭代器及其关联的引用/指针仅在将项目本身从容器中移除时才无效。std::forward_list
如果内存是一个严重的问题,那儿有吗。
如果担保太强,则std::deque
提供较弱但有用的担保。无效是由中间的插入导致的,但是在头部或尾部的插入只会导致迭代器无效,而不会导致对容器中项目的指针/引用无效。
std::vector
仅在最后提供廉价的插入(即使那样,如果您增加容量也会变得昂贵)。
std::list
就性能而言是昂贵的(每个新插入的项都需要分配内存),但是它是一致的。它还偶尔提供必不可少的功能,可以在不影响性能的情况下随机整理物品,以及与其他std::list
相同类型的容器交易物品而不会降低性能。如果您需要对周围的事物进行大量改组,请使用std::list
。
std::deque
在头部和尾部提供固定时间的插入/拔出,但在中间插入可能会相当昂贵。因此,如果您需要从正面和背面添加/删除东西,std::deque
可能就是您所需要的。
应该注意的是,由于移动语义的原因,std::vector
插入性能可能不会像以前那样糟糕。一些实现实现了一种基于移动语义的项目复制形式(所谓的“ swaptimization”),但是现在移动是语言的一部分,它是标准的强制要求。
std::array
如果您想要最少的动态分配,则是一个很好的容器。它只是C数组的包装;这意味着必须在编译时知道其大小。如果可以忍受,请使用std::array
。
话虽这么说,使用std::vector
和调整reserve
大小对于有界也同样适用std::vector
。这样,实际大小可能会有所不同,并且只有一个内存分配(除非您消耗了容量)。
std::sort
,还有std::inplace_merge
一个很有趣的地方就是可以轻松放置新元素(而不是std::lower_bound
+ std::vector::insert
调用)。很高兴了解flat_set
和flat_map
!
vector<bool>
是vector<char>
。
std::allocator<T>
不支持这种对齐方式(并且我不知道为什么不支持这种对齐方式),那么您始终可以使用自己的自定义分配器。
std::vector::resize
具有一个不带值的重载(它只是采用新的大小;任何新元素都将是就地默认构造的)。另外,为什么编译器即使声明为具有对齐方式也无法正确对齐值参数?
bitset
for bool,如果您事先知道大小,请访问en.cppreference.com/w/cpp/utility/bitset
快速旋转,尽管可能需要工作
Should the container let you manage the order of the elements?
Yes:
Will the container contain always exactly the same number of elements?
Yes:
Does the container need a fast move operator?
Yes: std::vector
No: std::array
No:
Do you absolutely need stable iterators? (be certain!)
Yes: boost::stable_vector (as a last case fallback, std::list)
No:
Do inserts happen only at the ends?
Yes: std::deque
No: std::vector
No:
Are keys associated with Values?
Yes:
Do the keys need to be sorted?
Yes:
Are there more than one value per key?
Yes: boost::flat_map (as a last case fallback, std::map)
No: boost::flat_multimap (as a last case fallback, std::map)
No:
Are there more than one value per key?
Yes: std::unordered_multimap
No: std::unordered_map
No:
Are elements read then removed in a certain order?
Yes:
Order is:
Ordered by element: std::priority_queue
First in First out: std::queue
First in Last out: std::stack
Other: Custom based on std::vector?????
No:
Should the elements be sorted by value?
Yes: boost::flat_set
No: std::vector
你可能会注意到,这不同于似地从C ++ 03版本,主要是由于这样的事实,我真的不喜欢链接节点。链接节点容器在性能上通常会被非链接容器击败,除了极少数情况下。如果您不知道这些情况是什么,并且有权使用Boost,请不要使用链接节点容器。(std :: list,std :: slist,std :: map,std :: multimap,std :: set,std :: multiset)。该列表主要侧重于中小型容器,因为(A)这是我们在代码中处理的99.99%,并且(B)大量元素需要自定义算法,而不是不同的容器。