定义最小尺寸的结构
Define struct with minimum size
我想定义一个结构,例如type
,使得 sizeof(type)
不小于某个值。
动机:
我有一个矢量 std::vector<type>
,我将从中删除一些元素。另外,我已经将一些元素的索引保存到其他地方,因此我只想将其标记为未使用并在将来重用它。这导致我将下一个可用位置保存为已删除位置的列表。因此,sizeof(type)
应该不少于 sizeof(size_t)
并且 type
也应该正确对齐。
可能的解决方案:
boost::variant<type, size_t>
从我的角度来看,这有两个问题。如果我use boost::get<type>
,性能会明显下降。如果我使用 boost::apply_visitor
,语法会很奇怪,根据我的个人资料,性能也会降低。
union{type t; size_t s;}
这当然有效,但有两个缺点。首先,引用 type
成员的语法会更混乱。其次,还要为这个union定义构造函数、拷贝构造函数等。
将 type
延长 char[sizeof(size_t) - sizeof(type)]
这几乎满足了我的要求。但是,这种零长度数组的风险不受 c++ 标准的支持,并且可能存在错误对齐的风险。
因为我不会像 size_t
那样经常使用 type
,所以我只想确保在需要时可以使用 reinterpret_cast<size_t>
。
互补
看完评论后,我认为对我的问题最好的解决方案应该是boost::variant
。但我仍然想知道是否有办法结合解决方案 2 和 3 的优点,即
一个。我可以访问 type
的成员而无需更改。
b。确保 reinterpret_cast<size_t>
有效。
您可以通过以下方式减轻对解决方案 3 的担忧:
struct data
{
// ...
};
template<class T, bool> class pad_;
template<class T> class pad_<T, true> { char dummy[sizeof(T) - sizeof(data)]; };
template<class T> class pad_<T, false> {};
template<class T> using pad = pad_<T, (sizeof(T) > sizeof(data))>;
class type : public data, pad<size_t>
{
// ...
};
此代码:
- 假定 empty base optimization 以便
pad
可以在 sizeof(data) >= sizeof(size_t)
时从 type
布局中完全优化
- 没有零长度数组的风险
虽然这是一个有趣的问题,但设计本身的接缝问题。
插入新元素时,标记为未使用的项目在增长向量之前首先被考虑。这意味着项目的相对顺序是不可预测的。如果这是可以接受的,你可以只使用一个(智能)指针向量。
通常情况下,向量在从中间移除项目时效率低下。由于顺序无关紧要,因此可以将要删除的元素与最后一个元素交换并弹出最后一个元素。
所有元素大小相同;使用池分配它们可能比使用系统分配器更快。
池基本上以大块分配内存,并根据要求分发较小的块。池通常将空闲列表存储在尚未分配的块中以跟踪可用内存(与问题中描述的想法相同)。有一些现成的好实现(来自 Boost 和其他来源)。
关于原始设计,由于实际元素与 "holes" 混合,因此枚举向量中的元素很麻烦,逻辑将被额外的检查混淆。
原始设计背后可能有一些卖点;不幸的是@user1535111 没有告诉细节。
我想定义一个结构,例如type
,使得 sizeof(type)
不小于某个值。
动机:
我有一个矢量 std::vector<type>
,我将从中删除一些元素。另外,我已经将一些元素的索引保存到其他地方,因此我只想将其标记为未使用并在将来重用它。这导致我将下一个可用位置保存为已删除位置的列表。因此,sizeof(type)
应该不少于 sizeof(size_t)
并且 type
也应该正确对齐。
可能的解决方案:
boost::variant<type, size_t>
从我的角度来看,这有两个问题。如果我
use boost::get<type>
,性能会明显下降。如果我使用boost::apply_visitor
,语法会很奇怪,根据我的个人资料,性能也会降低。union{type t; size_t s;}
这当然有效,但有两个缺点。首先,引用
type
成员的语法会更混乱。其次,还要为这个union定义构造函数、拷贝构造函数等。将
type
延长char[sizeof(size_t) - sizeof(type)]
这几乎满足了我的要求。但是,这种零长度数组的风险不受 c++ 标准的支持,并且可能存在错误对齐的风险。
因为我不会像 size_t
那样经常使用 type
,所以我只想确保在需要时可以使用 reinterpret_cast<size_t>
。
互补
看完评论后,我认为对我的问题最好的解决方案应该是boost::variant
。但我仍然想知道是否有办法结合解决方案 2 和 3 的优点,即
一个。我可以访问 type
的成员而无需更改。
b。确保 reinterpret_cast<size_t>
有效。
您可以通过以下方式减轻对解决方案 3 的担忧:
struct data
{
// ...
};
template<class T, bool> class pad_;
template<class T> class pad_<T, true> { char dummy[sizeof(T) - sizeof(data)]; };
template<class T> class pad_<T, false> {};
template<class T> using pad = pad_<T, (sizeof(T) > sizeof(data))>;
class type : public data, pad<size_t>
{
// ...
};
此代码:
- 假定 empty base optimization 以便
pad
可以在sizeof(data) >= sizeof(size_t)
时从 - 没有零长度数组的风险
type
布局中完全优化
虽然这是一个有趣的问题,但设计本身的接缝问题。
插入新元素时,标记为未使用的项目在增长向量之前首先被考虑。这意味着项目的相对顺序是不可预测的。如果这是可以接受的,你可以只使用一个(智能)指针向量。
通常情况下,向量在从中间移除项目时效率低下。由于顺序无关紧要,因此可以将要删除的元素与最后一个元素交换并弹出最后一个元素。
所有元素大小相同;使用池分配它们可能比使用系统分配器更快。
池基本上以大块分配内存,并根据要求分发较小的块。池通常将空闲列表存储在尚未分配的块中以跟踪可用内存(与问题中描述的想法相同)。有一些现成的好实现(来自 Boost 和其他来源)。
关于原始设计,由于实际元素与 "holes" 混合,因此枚举向量中的元素很麻烦,逻辑将被额外的检查混淆。
原始设计背后可能有一些卖点;不幸的是@user1535111 没有告诉细节。