The following question came up:
The c++ standard seems to say, that std::vector
requires a complete type to work. (See https://en.cppreference.com/w/cpp/container/vector ) Then, why does the following code still compile?
#include <vector>
struct parent;
struct child
{
std::vector<parent> parents; //parent is incomplete here!
};
struct parent
{
std::vector<child> children;
};
This seems counterintuitive. If std::vector
requires a complete type, then std::vector<parent>
should not compile because only its forward declaration is known inside the class definition of child
.
std::vector
does not require a complete type?EDIT
There seems to be a difference between c++11 and c++17. I would like to understand the c++11 version.
A vector will hold an object of a single type, and only a single type.
1) std::vector is a sequence container that encapsulates dynamic size arrays. 2) std::pmr::vector is an alias template that uses a polymorphic allocator. The elements are stored contiguously, which means that elements can be accessed not only through iterators, but also using offsets to regular pointers to elements.
A std::vector can never be faster than an array, as it has (a pointer to the first element of) an array as one of its data members. But the difference in run-time speed is slim and absent in any non-trivial program. One reason for this myth to persist, are examples that compare raw arrays with mis-used std::vectors.
An incomplete type is a type that describes an identifier but lacks information needed to determine the size of the identifier. An incomplete type can be: A structure type whose members you have not yet specified. A union type whose members you have not yet specified.
Standard says (draft N3690; this is post C++11, pre C++14):
[res.on.functions]
1 In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++standard library depends on components supplied by a C++program. If these components do not meet their requirements, the Standard places no requirements on the implementation.
2 In particular, the effects are undefined in the following cases:
— if an incomplete type (3.9) is used as a template argument when instantiating a template component, unless specifically allowed for that component.
Given that standard places no requirements, and effects are undefined (as far as I can tell, this is same as undefined behaviour), there is no expectation for the instantiation to "not work" any more than there is expectation for it to (appear to) "work".
Since C++17, the requirement was relaxed and std::vector
does not require the value type to be complete, if used with appropriate allocator (the default allocator is appropriate). (This freedom does not extend to using all member functions; they have additional requirements).
Standard quote (current draft):
[vector.overview]
An incomplete type T may be used when instantiating vector if the allocator meets the allocator completeness requirements. T shall be complete before any member of the resulting specialization of vector is referenced.
[allocator.requirements.completeness]
If X is an allocator class for type T, X additionally meets the allocator completeness requirements if, whether or not T is a complete type:
- X is a complete type, and
- all the member types of allocator_traits other than value_type are complete types.
[default.allocator]
All specializations of the default allocator meet the allocator completeness requirements ([allocator.requirements.completeness]).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With