在我的几个项目中,我越来越需要处理内存中连续的位序列 - 有效(*)。到目前为止,我已经写了一堆内联的独立函数,模板选择“位容器”类型(例如uint32_t
),用于获取和设置位,应用'或'和'和'到它们的值,定位容器,将位长转换为字节大小或容器中的长度等等......它看起来像是写字时间。
我知道C ++标准库具有std::vector<bool>
的特化,许多人认为它是一个设计缺陷 - 因为它的迭代器不会暴露实际的bool
,而是代理对象。无论这是一个好主意还是一个专业化的坏主题,它肯定是我正在考虑的事情 - 一个明确的位代理类,希望“总是”被优化掉(使用constexpr
的漂亮润滑, noexcept
和inline
)。所以,我在考虑可能从一个标准库实现中调整std::vector
代码。
另一方面,我想要的课程:
从这个意义上讲,它更像是一个用于比特的跨度类。那么也许从一个跨度开始呢?我不知道,跨度仍然不标准;并且没有跨越代理...
那么我的实现有什么好基础(编辑:不是基类)? std::vector<bool>
? std::span
?都?没有?或者 - 也许我正在重新发明轮子,这已经解决了问题?
注意:
std::bitset
。(*) - 到目前为止还没有SIMD效率,但可能会更晚。此外,这可能在CUDA代码中使用,我们没有SIMDize但假装通道是正确的线程。
答案 0 :(得分:1)
而不是std::vector
或std::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
方法这对你有用(大多数情况下,如果你有时使用编译时大小,并且可以专门化某些方法,以便在这种情况下更有效)。