在std :: vector <bool>上建立一个非拥有位容器是个好主意吗?的std ::跨度?

时间:2018-06-13 21:55:21

标签: c++ stdvector class-design c++20 std-span

在我的几个项目中,我越来越需要处理内存中连续的位序列 - 有效(*)。到目前为止,我已经写了一堆内联的独立函数,模板选择“位容器”类型(例如uint32_t),用于获取和设置位,应用'或'和'和'到它们的值,定位容器,将位长转换为字节大小或容器中的长度等等......它看起来像是写字时间。

我知道C ++标准库具有std::vector<bool>的特化,许多人认为它是一个设计缺陷 - 因为它的迭代器不会暴露实际的bool,而是代理对象。无论这是一个好主意还是一个专业化的坏主题,它肯定是我正在考虑的事情 - 一个明确的位代理类,希望“总是”被优化掉(使用constexpr的漂亮润滑, noexceptinline)。所以,我在考虑可能从一个标准库实现中调整std::vector代码。

另一方面,我想要的课程:

  • 永远不会拥有数据/位 - 它将接收起始位容器地址(假设对齐)和位长度,并且不会分配或释放。
  • 它无法动态调整数据或以其他方式调整数据 - 即使在保留相同数量的空间时也不会像std :: vector :: resize();它的长度将在其寿命/范围内固定。
  • 它不应该知道堆(并且在没有堆时工作)

从这个意义上讲,它更像是一个用于比特的跨度类。那么也许从一个跨度开始呢?我不知道,跨度仍然不标准;并且没有跨越代理...

那么我的实现有什么好基础(编辑:不是基类)? std::vector<bool>std::span?都?没有?或者 - 也许我正在重新发明轮子,这已经解决了问题?

注意:

  • 比特序列长度在运行时是已知的,而不是编译时间;否则,正如@SomeProgrammerDude建议我可以使用std::bitset
  • 我的班级不需要“be-a”span或“be-a”向量,所以我不打算专注于任何一个。

(*) - 到目前为止还没有SIMD效率,但可能会更晚。此外,这可能在CUDA代码中使用,我们没有SIMDize但假装通道是正确的线程。

1 个答案:

答案 0 :(得分:1)

而不是std::vectorstd::span我怀疑你的类的实现会与std::bitset共享更多共同点,因为它几乎是一样的,除了(固定的)运行时确定的大小。

实际上,您可以采用典型的std::bitset实现,并将<size_t N>模板参数作为size_t size_成员(或您喜欢的任何名称)移动到类中,然后您就可以了你的动态bitset类几乎没有变化。你可能想要摆脱任何你认为像std::string和朋友那样的构造者一样残酷的东西。

最后一步是删除底层数据的所有权:基本上你将删除构造函数中底层数组的创建,并使用一些指针维护现有数组的视图。

如果您的客户不同意用于存储的基础无符号整数类型(您称之为“位容器”),那么您可能还需要使您的类成为此类型的模板,尽管如果它更简单每个人都同意说uint64_t

std::vector<bool>而言,你并不需要太多:vector所做的一切,std::bitset可能也是如此:{{1}增加是动态增长 - 但你已经说过你不想要那样。 vector具有代理对象概念来表示单个位,但vector<bool>也是如此。

std::bitset您可以了解基础数据的非所有权,但我认为这实际上并不代表很多底层代码。您可能需要考虑{em> 编译时已知大小运行时提供的大小(由std::span表示)的std::span方法这对你有用(大多数情况下,如果你有时使用编译时大小,并且可以专门化某些方法,以便在这种情况下更有效)。