14

元组的伪成员的布局和内存对齐是否有任何正式规范?

无论如何修改元组中类型的内存对齐方式?它受#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);

如果我想将 typedefcTriangle用于std::tuple<uint32, uint32, uint32>元编程目的,我是否仍然能够读取/写入元组的原始内存(因此是元组的向量),或者该内存是否具有未知的对齐方式?

4

3 回答 3

15

不仅没有要求以任何特定方式排列对象,而且许多tuple实现实际上将第二个对象放在第一个对象之前。

于 2013-01-30T05:09:08.740 回答
14

元组通常不是标准布局,因为标准布局类在其继承层次结构中最多可以有一个具有非静态数据成员的类,实现可变参数的典型方法tuple是通过递归继承,每一级递归添加一个数据成员。这允许tuple实现通过对成员不可用的空基类优化来消除不同的空struct成员。

如果您检查sizeof(myTuple) == sizeof(myStruct),您有理由假设元组的内存布局以某种(一致的)顺序包含结构的元素,但实际上依赖于别名可能会导致未定义的行为。

如果你说你只是想tuple为元编程使用别名,你最好使用一个元编程库,比如Boost.Fusion,它允许你用它的成员注释结构类型:

#pragma pack(push)
#pragma pack(4)
struct cTriangle {
    uint32 Index[3];
};
#pragma pack(pop)
BOOST_FUSION_ADAPT_STRUCT(
    cTriangle,
    (uint32[3], Index))
于 2013-01-30T16:30:51.230 回答
1

正如大卫指出的那样,没有任何保证符合标准。但是,如果您对二值元组感兴趣,您可能想要使用std::pair<T1, T2>,它是标准布局(如果T1,T2是标准布局),因此具有可预测的内存布局。

另见C++0x 元组向后存储元素

[编辑]

抱歉,在回答您的评论之前,我没有看到 ecatmur 的回答。顺便说一句:如果你的结构的所有成员都具有相同的类型,你当然可以使用 std::array,这是标准布局,它允许使用类似于 std::tuple 的 std::get 访问元素。

于 2013-01-30T14:35:24.550 回答