c++ - 将非拥有位容器基于 std::vector 是个好主意吗? 标准::跨度?
问题描述
在我的几个项目中,我越来越需要处理内存中的连续位序列 - 高效(*)。到目前为止,我已经编写了一堆可内联的独立函数,以选择“位容器”类型(例如uint32_t
)为模板,用于获取和设置位,将“或”和“与”应用于它们的值,定位容器,以位为单位的长度转换为以字节为单位的大小或容器中的长度等......看起来这是编写类的时间。
我知道 C++ 标准库有一个专门化的std::vector<bool>
,这被许多人认为是一个设计缺陷——因为它的迭代器不暴露实际bool
的 s,而是代理对象。无论这对于专业化来说是一个好主意还是一个坏主意,这绝对是我正在考虑的东西 - 一个显式的位代理类,希望它“总是”被优化掉(用constexpr
,noexcept
和很好地润滑inline
)。因此,我正在考虑可能std::vector
从标准库实现之一改编代码。
另一方面,我的预期课程:
- 永远不会拥有数据/位-它将接收起始位容器地址(假设对齐)和位长度,并且不会分配或释放。
- 它将无法动态或以其他方式调整数据大小 - 即使在保留与 std::vector::resize() 相同的空间量时也不行;它的长度将在其生命周期/范围内固定。
- 它不应该对堆一无所知(并且在没有堆时工作)
从这个意义上说,它更像是位的跨度类。那么也许从跨度开始呢?我不知道,跨度仍然不标准;并且跨度中没有代理...
那么什么是我实现的良好基础(编辑:不是基类)?std::vector<bool>
? std::span
? 两个都?没有任何?或者 - 也许我正在重新发明轮子,这已经是一个已解决的问题?
笔记:
- 位序列长度在运行时是已知的,而不是编译时;否则,正如@SomeProgrammerDude 建议的那样,我可以使用
std::bitset
. - 我的班级不需要“成为”跨度或“成为”向量,所以我没有考虑专门研究其中任何一个。
(*) - 到目前为止,SIMD 效率不高,但可能会在以后出现。此外,这可以在我们不 SIMDize 而是假装通道是正确线程的 CUDA 代码中使用。
解决方案
而不是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
可能也会做:vector
增加的主要是动态增长——但你说过你不想要那个。vector<bool>
具有代表单个位的代理对象概念,但std::bitset
.
从std::span
您的基础数据的非所有权的想法,但我不认为这实际上代表了很多基础代码。如果这对您有用(主要是如果您有时使用编译时大小并且可以将某些std::span
方法专门化为更多在这种情况下有效)。Extent == std::dynamic_extent
推荐阅读
- scala - Spark:展平简单的多列 DataFrame
- c - C中Union Struct的动态数据结构
- sql - 从视图或表格中选择有区别吗?
- javascript - 使用 VueJs 绑定内联动态 css 类名
- .net - VB 2010 ListviewItemCheck
- python - matplotlib中固定大小的矩形?
- r - ggplot2:为多列添加 p 值、Rsq 和斜率
- f# - 使用相互递归辅助函数的 F# 函数
- python-3.x - 将值动态插入 API 请求?
- .net-core - 更改证书是否会使使用 IdentityServer4.Models.Secret Sha256() 方法生成的所有机密无效?