尺寸和类型,保证
sizeof and types, guarantees
我找不到以下代码片段没有设计缺陷的证据/证明,谈到了正确性。
template <class Item>
class MyDirtyPool {
public:
template<typename ... Args>
std::size_t add(Args &&... args) {
if (!m_deletedComponentsIndexes.empty()) {
//reuse old block
size_t positionIndex = m_deletedComponentsIndexes.back();
m_deletedComponentsIndexes.pop_back();
void *block = static_cast<void *> (&m_memoryBlock[positionIndex]);
new(block) Item(std::forward<Args>(args) ...);
return positionIndex;
} else {
//not found, add new block
m_memoryBlock.emplace_back();
void *block = static_cast<void *> (&m_memoryBlock.back());
new(block) Item(std::forward<Args>(args) ...);
return m_memoryBlock.size() - 1;
}
}
//...all the other methods omitted
private:
struct Chunk {
char mem[sizeof(Item)]; //is this sane?
};
std::vector<Chunk> m_memoryBlock; //and this one too, safe?
std::deque<std::size_t> m_deletedComponentsIndexes;
};
我关心Chunk的所有东西,它在这里本质上是一个与所提供类型大小相同的内存袋。我不想在m_memoryBlock
中显式地创建Item对象,因此我需要某种"有足够空间的内存块"。
我能确定Chunk的大小与提供的类型相同吗?请提供一些这个假设不起作用的例子。
如果我的假设完全错误,我应该如何处理?
在这样的设计中,内存必须与您想要在那里创建的对象类型适当对齐。
标准内置类型通常具有自然对齐,这等于它们的sizeof
,即sizeof(T) == alignof(T)
。
char
数组的对齐方式是1字节,这对于其他任何操作都是不够的。
强制对齐的一个简单方法是像这样使用std::max_align_t
:
union Chunk
{
std::max_align_t max_align;
char mem[sizeof(Item)];
};
这将使Chunk::mem
适合于任何标准的内置类型。
另一种方法是使用C++11alignas
关键字对要放置在char
数组中的类型进行精确对齐:
struct Chunk
{
alignas(Item) char mem[sizeof(Item)];
};
这正是std::aligned_storage
为您所做的。
然而,这将需要暴露Item
的定义,这在某些情况下可能是不方便或不希望的。
例如,这种方法可以用作Pimpl习惯用法的优化,以避免内存分配,然而,这将需要在头文件中公开实现的定义,以获得其大小和对齐方式,从而违背Pimpl的目的。有关更多详细信息,请参阅"快速Pimpl习语"。
另一个细节是,如果您想复制/移动Chunk
,并希望存储的对象保持有效,那么这些存储的对象必须是可复制的,例如
static_assert(std::is_trivially_copyable<Item>::value,
"Item cannot be copied byte-wise");
typedef std::aligned_storage<sizeof(Item), alignof(Item)> Chunk;
对于内存池,std::vector<Chunk>
不是一个好的选择,因为在重新分配时,当向量增长时,存储在池中的对象的所有指针和引用都将无效。
对象不应在通用内存池中移动。
- C++默认情况下,指针类型数组的元素是否保证初始化为 nullptr?
- 对象地址是否保证是其类型对齐的倍数
- 如果条件取决于模板类型并且在编译时已知,是否可以保证C++编译器不会生成分支?
- UINTX_T和INTX_T类型的打印保证
- 在英特尔上自然对齐的POD类型的保证原子操作
- C++标准是否保证了没有虚拟成员函数的类类型的大小
- wchar_t保证与任何整数类型不同
- 获取保证通过不同类型的向量进行索引的size_type
- 封装内置C++类型以保证初始化
- 我是否可以保证SizeOf(type)== sizeof(无符号类型)
- 如何保证C++类型的位数
- 尺寸和类型,保证
- 是保证字符以外的任何类型的大小
- 新字符是否实际上保证类类型的对齐内存
- 该标准是否提供了有关从基本类型迁移的任何保证
- 哪些 std 类型在移动构造函数中用作 arg 后保证为空/空
- 是否保证默认构造函数将内置类型自动初始化为0
- 在c++中,对于所有容器类型,std::end都保证为0(1)
- typeid()是否足以保证类型安全
- 枚举的基础int类型是否有一个保证的宽度