dimanche 7 août 2022

Does the standard require that std::array

std::array is required by the standard to be well-defined even when the size is zero, so that std::array<T, 0> is well-defined even though int[0] is not allowed (though GCC implements an extension for it).

However, on GCC, Clang, and MSVC, std::array<T, 0> is not treated as if it is a zero-sized struct, i.e. it does not act like it has trailing padding, and so [[no_unique_address]] and the empty base optimization does not work with it. For example:

#include <array>

struct Tester {
    [[no_unique_address]] std::array<char, 0> arr;
    char c;
};

struct Tester2 : std::array<char, 0> {
    char c;
};

// true on GCC, Clang, and MSVC at least:
static_assert(sizeof(Tester) == 2);
static_assert(sizeof(Tester2) == 2);

This is surprising, since it's obviously implementable as an empty struct. Is this something mandated by the standard?


Note: I've looked into the code for libstdc++, and it works like this because std::array<char, 0> contains an instance of an empty struct that is not [[no_unique_address]] and not using empty base class optimization, i.e. it looks something like this:

template <typename T>
struct array<T, 0> {
    struct {} empty; // no [[no_unique_address]]!
};

But this doesn't doesn't explain why it was designed this way. Even though [[no_unique_address]] wasn't a thing until C++20, the empty base class optimization is used liberally in other parts of the standard library, so it's definitely something that could be done if desired.

Aucun commentaire:

Enregistrer un commentaire