【问题标题】:C++ STL stack vs forward_listC++ STL 堆栈与 forward_list
【发布时间】:2021-12-20 15:18:40
【问题描述】:

我有一个用例,我需要以无特定顺序存储一些 uint16_t 变量(尽管变量的实际类型不相关)。我决定求助于 STL 来寻找最适合我需要的容器。

容器中的物品可能会被取出使用并放回容器中。有点像机械师可能会有一盒螺丝刀,而不是把螺丝刀放在口袋里。容器不需要对存储的对象进行任何排序,取出什么都没有关系——唯一的要求是知道容器中是否还有任何东西。

我的目光转向std::stackstd::forward_list。它们都提供了 O(1) 插入(只是改变前面的元素)和 O(1) 的弹出操作(同样,只是改变前面的元素并返回前一个前面)。问题是 - 我不知道它们在概念上有何不同。

我知道std::stack 是一个仅包装实际 STL 容器的适配器(默认为 std::deque),因此它可能会产生一些意外开销,具体取决于被包装的容器。

我倾向于使用std::forward_list,但我正在寻找同事的意见。如果您对此事有任何想法,请分享。

【问题讨论】:

  • 几乎总是std::vector,除非您可以测量差异。从 45:48 观看 channel9.msdn.com/Events/Build/2014/2-661 了解原因。
  • @RichardCritten 容器需要是静态常量。在没有 gnu::constructor 或 #pragma 启动的情况下,我可以在代码中调用 vector.reserve()。

标签: c++ stl stack singly-linked-list forward-list


【解决方案1】:

TLDR: 如果您只需要添加/删除最后一个元素,请使用向量或堆栈。这是最快的选择,并且开销最低。

长版:查找链表和动态数组之间的比较,例如这里:vector vs. list in STL

大部分讨论都是关于 std::list 但同样的原则也适用于 forward_list

开销和操作的简短说明

向量数据结构:

  • 1 个动态分配的数组
  • 1 个整数,表示使用的元素数
  • 1 个整数,表示可用元素的数量(预分配大小)

(脚注:实际上不是计数器而是指针。我们不用担心)。

在向量末尾追加一个元素:

  1. 检查是否有可用空间。如果不是,则重新分配两倍于当前大小的数组。由于向量增长到两倍大小(指数增长),这种情况非常罕见,不会对性能产生太大影响。
  2. 将元素复制到数组中的索引
  3. 增加计数器

从向量末尾移除一个元素:

  1. 递减计数器。就是这样(除非你有析构函数)

内存开销: 24 字节用于指针和计数器。 8 字节用于数组的动态分配。最坏情况下 50% 未使用的元素。

转发列表数据结构:

  • 1 个指向第一个元素的指针
  • 1 个指向最后一个元素的指针
  • 在每个元素中,1 个指向下一个元素的指针

转发列表插入:

  1. 动态分配新元素(昂贵)
  2. 设置指针(便宜)

删除第一个元素:

  1. 将指针从第一个元素更改为第二个元素
  2. 释放元素(昂贵)

动态分配的计算开销远高于向量使用的任何东西。

内存开销:

  • 16 字节用于基结构中的两个指针
  • 每个元素 8 字节用于动态分配,8 字节用于指向下一个元素的指针,6 字节填充,因为分配器仅适用于 8 字节的倍数

对于每 2 个字节使用的有效负载,与向量中的 2-for-2 最坏情况相比,有 22 个字节的开销!

【讨论】:

  • en.cppreference.com/w/cpp/container/stack 声明模板参数“Container”默认为 std::deque。网站错了吗?
  • 我读了你的例子,我更倾向于使用 std::forward_list 而不是 vector
  • @selama:关于堆栈:你是对的。这是一个奇怪的决定。带有矢量的堆栈会更好,但无论如何。仅使用矢量的另一个原因。关于 forward_list,您认为它对您的案例更有用吗?
  • 我不关心中间插入。我唯一担心的是:快速插入前面,从前面快速弹出。我不需要知道容器的大小或插入中间。单链表看起来很自然。 Vector 具有更多功能,这让我认为它还需要一些开销来支持这些额外功能。
  • 在概念上相同的用例中比较 vector 和 forward_list 的基准。 Vector 快 4.1 倍。我有 0 线索为什么,但基准就是基准。
猜你喜欢
  • 1970-01-01
  • 2012-01-18
  • 2016-07-03
  • 2011-02-06
  • 1970-01-01
  • 2014-06-23
  • 2012-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多