为什么sizeof(std :: variant)的大小与具有相同成员的struct相同?

时间:2017-08-08 18:47:35

标签: c++ unions c++17

类模板std::variant表示类型安全联合。在任何给定时间std::variant的实例或者保存其替代类型之一的值,或者它没有值。

sizeof(std::variant<float, int32_t, double>) == 16

但如果它是一个联盟,为什么需要这么多空间呢?

struct T1 {
    float a;
    int32_t b;
    double c;
};

struct T2 {
    union {
        float a;
        int32_t b;
        double c;
    };
};

变体与struct

的大小相同
sizeof(T1) == 16
sizeof(T2) == 8

我希望联合的大小加上4个字节来存储,哪种类型是活动的。

4 个答案:

答案 0 :(得分:20)

此处col-*-*中具有最大对齐的类型为variant,对齐为8.这意味着整个double必须具有8的对齐。这也意味着它大小必须是8的倍数,以确保每个variant数组中的variant将与8对齐。

但是变体必须存储的不仅仅是最大的类型:它还必须存储标识符或标记以了解当前实例化的类型。因此,即使只有1个字节用于该标识符,整个结构也会填充为16,因此它是8的倍数。

更正确的比较是:

double

答案 1 :(得分:7)

基本答案是:出于校准原因。由于您的一个类型是double,而双精度是8字节,具有8字节对齐要求,这意味着该变体还具有8字节对齐要求。所以它只能是8个字节的倍数。正如您自己所指出的,最小尺寸是最大类型+另外一些指示哪个成员处于活动状态。这意味着它不能适合8个字节,但是对齐要求会一直强制到16个字节。

这就是为什么它不能是12字节,正如你的理由。顺便说一句,也没有规则说活动类型存储必须是4个字节。事实上,很明显,在绝大多数情况下,你可以使用单个字节,可以区分255种类型,加上空状态。我们可以测试一下:

struct null {};
std::cerr << sizeof(std::variant<bool, null>);

我刚刚在coliru上测试了它,它打印出“2”。在这种情况下,最大类型(bool)为1个字节,1个字节用于确定哪个类型处于活动状态。

答案 2 :(得分:4)

虽然变体在逻辑上是类型安全的联合,但不保证它们的大小等于具有相同成员的原始联合的大小。

很明显,由于变体(与原始联合不同)需要存储当前活动类型的信息,因此它必须更大。变体的实际大小取决于体系结构(填充)和实现,因为Standard对大小没有限制。

答案 3 :(得分:3)

有趣的是,你被巧合欺骗了。以下的返回是16:

sizeof(std::variant<float, int32_t, double, int64_t>)

这也是:

sizeof(std::variant<float, int32_t, double, int64_t, double>)

所以基本上std::variant中有一个内部变量,其大小为8字节(或更小,但与8字节对齐)。除了你的工会之外,还有16岁。