标准库中的tuple内存对齐

16

对于元组的伪成员,是否存在布局和内存对齐的正式规范?

有没有办法修改元组中类型的内存对齐方式? #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 typedef为 std :: tuple & lt; uint32,uint32,uint32&gt; ,那么我是否仍然能够读/写元组(因此是元组向量)的原始内存,或者该内存具有未知对齐方式?

2
只是出于好奇,还是有什么问题需要我们帮忙解决? - GManNickG
@GManNickG,我实际上想看看是否可以使用元组作为结构体的替代,并将它们放入一个向量中,这样我就可以一次性读取和写入所有元素,而不是逐个元素、逐个元组参数地进行。我将更新主帖以包含一个示例。 - NtscCobalt
3个回答

18

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


我会点赞,因为这很有用,但它并没有回答我关于内存布局的主要问题。 - NtscCobalt
6
我已回答过了。三个问题的答案都是“不”。布局未指定,很多实际应用所使用的布局与你想要的布局完全不同。 - David Schwartz
我已经添加了一个我想要实现的示例。由于您提到顺序未指定,因此我无法像当前尝试在编译器之间使用元组,但我仍然想知道元组成员的对齐方式。 - NtscCobalt
它可以是任何东西。没有要求。这些不是你要找的机器人。 - David Schwartz
谢谢,最初我标记了这个作为答案,但我决定标记ecatmur的,因为它解释了一般元组实现以及为什么不可能。我想其他任何遇到这个问题的人都会从他的回答中获得更多信息。如果我可以标记两个,我会的,抱歉。 - NtscCobalt

15

元组通常不是标准布局,因为标准布局类的继承体系中最多只能有一个带有非静态数据成员的类,而实现可变参数 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))

1
正如David所指出的,根据标准没有任何保证。然而,如果您对于一个包含两个值的元组感兴趣,您可以使用 std::pair<T1, T2>,它是标准布局(如果T1,T2是标准布局),因此具有可预测的内存布局。
另请参见C++0x Tuples Store Elements Backwards [编辑]
抱歉,在回答您的评论之前我没有看到ecatmur的回答。顺便说一下:如果您的结构的所有成员都具有相同的类型,则当然可以使用std::array,它是标准布局,并且允许使用类似于std::tuple的std::get进行元素访问。

那么,如果元组的所有模板参数都是标准布局,为什么它们不是标准布局呢?是否有可能编写一个允许标准布局的元组模板? - NtscCobalt
我认为,原因是元组通常作为递归继承层次结构实现的。这样,包含 N 个成员的元组派生自具有 N-1 个成员加上元素 N 类型的元组。因此,成员分布在几个派生类中,违反了 标准布局 概念的要求 5。我不确定是否可能实现一个元组,它允许可变数量的成员,而不违反标准布局概念。 - Claas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接