47

Consider the following piece of code, which is perfectly acceptable by a C++11 compiler:

#include <array>
#include <iostream>

auto main() -> int {
  std::array<double, 0> A;

  for(auto i : A) std::cout << i << std::endl;

  return 0;
}

According to the standard § 23.3.2.8 [Zero sized arrays]:

1 Array shall provide support for the special case N == 0.

2 In the case that N == 0, begin() == end() == unique value. The return value of
data() is unspecified.

3 The effect of calling front() or back() for a zero-sized array is undefined.

4 Member function swap() shall have a noexcept-specification which is equivalent to noexcept(true).

As displayed above, zero sized std::arrays are perfectly allowable in C++11, in contrast with zero sized arrays (e.g., int A[0];) where they are explicitly forbidden, yet they are allowed by some compilers (e.g., GCC) in the cost of undefined behaviour.

Considering this "contradiction", I have the following questions:

  • Why the C++ committee decided to allow zero sized std::arrays?

  • Are there any valuable uses?

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
101010
  • 41,839
  • 11
  • 94
  • 168
  • 21
    Probably to be consistent with the containers and make some generic stuff easier. – chris Jun 10 '14 at 23:27
  • 1
    One consideration might be that even if any implementations have difficulties with zero-sized arrays, they should have no difficulty with a partial specialisation for `std::array`. –  Jun 10 '14 at 23:29
  • 3
    Template meta-programs are often recursive, and it is often simplest to have the recursion bottom out at 0 rather than 1... But I admit I am having trouble constructing a realistic example in this case – Nemo Jun 10 '14 at 23:39
  • What about to return from a function? Say a function has an array return type but has the possibility of returning nothing. A zero length array would be useful because you can check `array.empty()` – Fantastic Mr Fox Jun 10 '14 at 23:43
  • 17
    Zero is a perfectly fine natural number. It would be weird if you *couldn't* have zero-sized arrays. The fact that C arrays don't allow size zero is more of a pragmatic limitation rather than desirable per se. Are there use cases? Yes, it means you don't have to special-case lots of generic constructions. – Kerrek SB Jun 10 '14 at 23:45
  • As far as I know, `std::array` has no practical value. – BЈовић Jun 11 '14 at 06:48
  • 3
    @KerrekSB Zero is not a *natural* number. Only non-negative & integer. – Display Name Jun 11 '14 at 11:40
  • 6
    @SargeBorsch actually, it depends on [the definition you choose](http://mathworld.wolfram.com/NaturalNumber.html), and it very much depends on practical reasons. – Davidmh Jun 11 '14 at 14:42
  • 1
    @SargeBorsch: Mr Peano would disagree :-S – Kerrek SB Jun 11 '14 at 17:21
  • @Davidmh that means, the use of this name should be avoided, because it's ambiguous. – Display Name Jun 11 '14 at 17:55

4 Answers4

47

If you have a generic function it is bad if that function randomly breaks for special parameters. For example, lets say you could have a template function that takes N random elements form a vector:

template<typename T, size_t N>
std::array<T, N> choose(const std::vector<T> &v) {
   ...
}

Nothing is gained if this causes undefined behavior or compiler errors if N for some reason turns out to be zero.

For raw arrays a reason behind the restriction is that you don't want types with sizeof T == 0, this leads to strange effects in combination with pointer arithmetic. An array with zero elements would have size zero, if you don't add any special rules for it.

But std::array<> is a class, and classes always have size > 0. So you don't run into those problems with std::array<>, and a consistent interface without an arbitrary restriction of the template parameter is preferable.

sth
  • 222,467
  • 53
  • 283
  • 367
4

One use that I can think of is the return of zero length arrays is possible and has functionality to be checked specifically.

For example see the documentation on the std::array function empty(). It has the following return value:

true if the array size is 0, false otherwise.

http://www.cplusplus.com/reference/array/array/empty/

I think the ability to return and check for 0 length arrays is in line with the standard for other implementations of stl types, for eg. Vectors and maps and is therefore useful.

Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
  • 14
    Please to not reference cplusplus.com. Most entries are incomplete or wrong. Use http://en.cppreference.com/w/cpp/container/array instead. – Kijewski Jun 10 '14 at 23:50
  • 4
    @Kay But its not in this case? Also when is it incomplete or wrong? – Fantastic Mr Fox Jun 10 '14 at 23:52
  • @Kay I see it occasionally incomplete on more obscure things-- but wrong? When? – druckermanly Jun 11 '14 at 00:29
  • The related discussion is here: http://meta.stackexchange.com/questions/194788/links-being-changed-to-cppreference-com, in particular I recommend this answer: http://meta.stackexchange.com/a/194792/231717 – BartoszKP Jun 11 '14 at 09:29
  • 3
    @BartoszKP That question has equal comments debating whether cplusplus.com is correct and overall looks like there is some agreement that it has gotten better. There are also examples given about where cppreference.com is wrong. Basically it boils down to, the link i provided may be to cplusplus.com but it is correct in its information and therefore there shouldn't be a problem. – Fantastic Mr Fox Jun 11 '14 at 22:33
  • @Ben Yes, you're right (not counting the unjustified plural when mentioning "examples" of when cppreference was wrong). – BartoszKP Jun 12 '14 at 08:15
1

As with other container classes, it is useful to be able to have an object that represents an array of things, and to have it possible for that array to be or become empty. If that were not possible, then one would need to create another object, or a managing class, to represent that state in a legal way. Having that ability already contained in all container classes, is very helpful. In using it, one then just needs to be in the habit of relating to the array as a container that might be empty, and checking the size or index before referring to a member of it in cases where it might not point to anything.

Dronz
  • 1,970
  • 4
  • 27
  • 50
1

There are actually quite a few cases where you want to be able to do this. It's present in a lot of other languages too. For example Java actually has Collections.emptyList() which returns a list which is not only size zero but cannot be expanded or resized or modified.

An example usage might be if you had a class representing a bus and a list of passengers within that class. The list might be lazy initialized, only created when passengers board. If someone calls getPassengers() though then an empty list can be returned rather than creating a new list each time just to report empty.

Returning null would also work for the internal efficiency of the class - but would then make life a lot more complicated for everyone using the class since whenever you call getPassengers() you would need to null check the result. Instead if you get an empty list back then so long as your code doesn't make assumptions that the list is not empty you don't need any special code to handle it being null.

Tim B
  • 40,716
  • 16
  • 83
  • 128