元组的伪成员的布局和内存对齐是否有正式规范?
有没有修改元组中类型的内存对齐?它是否受#pragma pack()指令影响?
例如:
typedef std::tuple<uint8_t, uint32_t> myTuple;
是否有任何规范说这将在内存中与:
相同#pragma pack() // Default packing
struct myStruct
{
uint8_t first;
uint32_t second;
}
道歉,如果这是一个愚蠢的问题,但在模板方面我并不完全理解对齐。
编辑:我正在尝试完成的示例
目前我有一些......
#pragma pack(push)
#pragma pack(4)
struct cTriangle
{
uint32 Index[3];
};
#pragma pack(pop)
template <class T>
inline bool Read(cFileStream& fStream, std::vector<T>& vec)
{
if (!vec.size())
return true;
// fStream.Read(void* pBuffer, size_t Size)
// Just a wrapper around a binary ifstream really
return fStream.Read(&vec[0], sizeof(T) * vec.size());
}
std::vector<cVector3> vPoint;
vPoint.resize(Verticies);
bool result = Read(FileStream, vPoint);
如果我想将cTriangle
命名为std::tuple<uint32, uint32, uint32>
作为元编程目的,我仍然可以读取/写入元组的原始内存(因此是元组的向量)或者是那个内存未知对齐?
答案 0 :(得分:12)
元组通常不是标准布局,因为标准布局类在其继承层次结构中最多只能有一个具有非静态数据成员的类,而实现可变参数tuple
的典型方法是通过递归继承,每个递归级别添加一个数据成员。这允许tuple
实现通过空基类优化来消除不同的空成员,这对struct
成员不可用。
如果你检查sizeof(myTuple) == sizeof(myStruct)
,你有理由假设元组的内存布局以某种(一致的)顺序包含结构的元素,但实际上依赖它来进行别名可能会导致未定义行为。
如果你说你只想用tuple
进行元编程的别名,你最好使用一个元编程库,例如Boost.Fusion,它允许你用它的成员注释结构类型: / p>
#pragma pack(push)
#pragma pack(4)
struct cTriangle {
uint32 Index[3];
};
#pragma pack(pop)
BOOST_FUSION_ADAPT_STRUCT(
cTriangle,
(uint32[3], Index))
答案 1 :(得分:10)
不仅没有要求以任何特定方式排列对象,而且许多tuple
实现实际上将第二个对象放在第一个对象之前。
答案 2 :(得分:1)
大卫指出,根据标准,无法保证。但是,如果您对两个值元组感兴趣,则可能需要使用std::pair<T1, T2>
,这是标准布局(如果T1,T2
是标准布局),因此具有可预测的内存布局。
另见C++0x Tuples Store Elements Backwards
[编辑]
抱歉,在回答您的评论之前,我没有看过ecatmur的回答。顺便说一句:如果你的struct的所有成员都有相同的类型,你当然可以使用std :: array,它是标准布局,允许使用std :: get进行元素访问,类似于std :: tuple。