Как выглядит структура памяти std::vector std:: option?

У меня есть std::vector из std::variant типы размещены в стеке. Поскольку размер каждого варианта является переменным. Мне интересно, какова структура памяти вектора в стеке.

1 ответ

Типы "std: variant" в C++ имитируют старые добрые "union" типы C (или, точнее, записи с тегами pascal), что означает, что все они имеют одинаковый размер, с той лишь разницей, что значения std :: variant имеют дополнительную информацию, связанную с ними, эта информация отслеживает альтернативные варианты. Точная реализация std :: variant зависит от платформы и, боюсь, не переносима.

Реализация в Visual C++ для std :: variant очень сложна (примерно 86 Кбайт кода мета-шаблона). Но мы можем угадать некоторые детали реализации с помощью простых тестов:

      #include <stdio.h>
#include <cstdint>
#include <variant>

template <typename T>
void Dump(T val)
{
    printf("Size %zu: Data:",sizeof(val));
    for (int i = 0; i < sizeof(val); ++i) printf(" %02X", (reinterpret_cast<std::uint8_t*>(&val))[i]);
    printf("\n");
}

#pragma pack(push, 1)
typedef struct { std::variant<std::uint32_t, std::uint64_t> u; } dummy_variant_t;
#pragma pack(pop)

int main(int, char*[])
{
    dummy_variant_t abc;

    //                _______________________ __ ?? ?? ?? ?? ?? ?? ?? <-- unknown info
    // Size 16: Data: EF CD AB 89 67 45 23 01 01 13 EC 00 02 00 00 00
    //                ^variant data           ^tag(uint64_t)
    abc.u = static_cast<std::uint64_t>(0x123456789ABCDEF);
    Dump(abc);

    //                ___________ xx xx xx xx __ ?? ?? ?? ?? ?? ?? ?? <-- unknown info
    // Size 16: Data: 78 56 34 12 67 45 23 01 00 13 EC 00 02 00 00 00
    //                ^           ^garbage    ^tag(uint32_t)
    //                |
    //                +variant data
    abc.u = static_cast<std::uint32_t>(0x12345678);
    Dump(abc);

    return 0;
}

Здесь мы видим, что этот конкретный тип std :: variant примерно соответствует:

      struct variant_t
{
    union
    {
        std::uint32_t m_Variant1;
        std::uint64_t m_Variant2;
    }
    m_VariantData;
    std::uint8_t m_Tag;
    std::uint8_t m_Unknown[7];
};

Итак, я надеюсь, что это поможет вам точно определить ваш типаж. Эти типы были у Паскаля давным-давно (почти с самого начала), см. Этот отрывок из руководства freepascal

Другие вопросы по тегам