7

It's a well-known fact that the C++ standard library containers, in general, cannot be instantiated with incomplete types. The result of doing so is UB, although in practice a given implementation will either accept the code without issues or issue a compilation error. Discussion about this restriction can be found here: Why C++ containers don't allow incomplete types?

However, in C++17, there are three containers that explicitly allow incomplete types: std::forward_list (26.3.9.1/4), std::list (26.3.10.1/4), and std::vector (26.3.11.1/4).

This is the result of N4510. The paper notes that "based on the discussion on the Issaquah meeting" the decision was made to, at least at first, limit such support to those three containers. But why?

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • 3
    Those containers only need a *pointer* to the type of object being stored. For a pointer to a type you don't need the full definition. – Some programmer dude Sep 12 '19 at 16:36
  • 3
    I'm actually surprised that `std::forward_list` and `std::list` allow it since their nodes could store the object by value. I guess the *T shall be complete before any member of the resulting specialization of list is referenced.* "fixes" that. – NathanOliver Sep 12 '19 at 16:45
  • @Someprogrammerdude What about `std::deque`? I don't see any reason for `deque` to demand type to be complete in advance as it is essentially a hybrid of `list` and `vector`. – user7860670 Sep 12 '19 at 16:53

2 Answers2

1

Because we know how to implement those containers to deal with incomplete types, without breaking the ABI.

std::array, on the other hand, needs to know how big an element is (for example).

Barry
  • 286,269
  • 29
  • 621
  • 977
Marshall Clow
  • 15,972
  • 2
  • 29
  • 45
  • 1
    Q. Doesn't vector also need to know to object size? Surely the default allocator works based on object size. – Mansoor Sep 12 '19 at 16:43
  • [N3890](http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3890.html) seems to indicate that it's possible for all containers other than `std::array`. – Brian Bi Sep 12 '19 at 16:43
  • 2
    libc++ could add support for additional containers - _if_ we were willing to change the ABI for those containers - which we're not. – Marshall Clow Sep 12 '19 at 16:45
  • @NathanOliver (I'm sure I could find out myself by reading the source) If you wanted to increment to the next element, how could you do so without knowing the size? – Mansoor Sep 12 '19 at 16:46
  • 1
    @Mansoor That is where the *T shall be complete before any member of the resulting specialization of list is referenced.* language comes into play. To just instantiate the class, you don't need to know `T`. To actually use the class you do, but the standard requires it to be complete before use. – NathanOliver Sep 12 '19 at 16:47
  • @NathanOliver Ahhh, well that clarifies that. Thanks :) – Mansoor Sep 12 '19 at 16:49
  • @NathanOliver That *T shall be complete before..."* opens the door to many usages, not only containers. And reduces "incomplete type" error to meaning "you didn't provided enough code". – Ripi2 Sep 12 '19 at 16:54
  • re ABI breakage, N3890 says there would be ABI breakage with libc++'s deque, but doesn't make similar claims about, say, unordered_map. – Brian Bi Sep 12 '19 at 16:54
1

But why?

The reason incomplete types weren't allowed in the standard containers was that some containers can work with them, but some don't. They didn't want to think too much about this issue at the time and made a blanket prohibition of incomplete types in all standard containers.

Matt Austern documented that in his great article "The Standard Librarian: Containers of Incomplete Types", which is no longer available, but there are still quotes from it in Boost Containers of Incomplete Types.

This C++17 change does justice by undoing the harm inflicted by that blanket prohibition.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • 1
    The allowance C++17 made is kind of retrospective in that way, I don't know an implementation of those which doesn't allow incomplete type due to syntax. Quite a number of people were relying on it or on boosts's variant. – Swift - Friday Pie Sep 12 '19 at 17:14