16

In libc++, the specialization of std::array<T,0> has a member (const) char array, which is aligned and sized according to T (source). I wonder what is the reason for this implementation since this member (__elems_) does not seem to be used anywhere. For comparison, libstdc++ uses an empty member, and Microsoft STL uses an empty member if T is not default-constructible (otherwise, it creates a single-element array).

Live demo of the difference: https://godbolt.org/z/1o167na6z

ks1322
  • 33,961
  • 14
  • 109
  • 164
Daniel Langr
  • 22,196
  • 3
  • 50
  • 93
  • Why is `array` even a thing? – Aykhan Hagverdili May 11 '23 at 08:45
  • 2
    @AyxanHaqverdili makes generic programming eaiser – Alan Birtles May 11 '23 at 08:46
  • I would guess that they aren't particularly concerned with how the size zero case behaves – Caleth May 11 '23 at 08:48
  • 1
    @AlanBirtles I am unconvinced that allowing instantiation of a generic function that effectively achieves nothing is beneficial. – Aykhan Hagverdili May 11 '23 at 08:48
  • 4
    @Ayxan - It saves *you* from specializing for size 0. Just loop over the array elements, and it works. Same reason for allowing `new int[0]` - it returns a pointer to no elements. – BoP May 11 '23 at 08:51
  • 5
    @AyxanHaqverdili off the top of my head one use case could be a structure with a fixed size cache, having a cache of size 0 would be perfectly valid – Alan Birtles May 11 '23 at 08:51
  • 5
    @AyxanHaqverdili Another example might be a template that is recursively instantiated with the base case that involves 0. – Daniel Langr May 11 '23 at 08:53
  • @DanielLangr Hmm. I feel like it might lead to more harm than good by allowing potentially unexpected cases to go unnoticed. I don't usually expect an array to be empty, but maybe that's just me. – Aykhan Hagverdili May 11 '23 at 08:56

1 Answers1

10

std::array is allowed to have a zero size but the underlying c arrays can't be zero-sized. Therefore the implementations will need some special case to handle this.

The standard doesn't specify what this implementation must be or really place many constraints on the behaviour, calling front() or back() is undefined behaviour. There is one constraint that array.begin() == array.end(). As there are not many constraints you'd expect different implementations to use different workarounds for it.

Libc++ originally used a single element array but this doesn't work with non-default constructible types. In order to maintain ABI compatibility this was replaced with a char array of the same size.

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60