Почему на земле работает следующий фрагмент кода?
struct A {
std::vector<A> subAs;
};
A - неполный тип, верно? Если бы был вектор A * s, я бы понял. Но здесь я не понимаю, как это работает. Кажется, это рекурсивное определение.
Почему на земле работает следующий фрагмент кода?
struct A {
std::vector<A> subAs;
};
A - неполный тип, верно? Если бы был вектор A * s, я бы понял. Но здесь я не понимаю, как это работает. Кажется, это рекурсивное определение.
Этот paper был принят в С++ 17, который позволяет неполные типы, которые будут использоваться в некоторых контейнерах STL. До этого было Undefined Поведение. Процитировать из статьи:
Основываясь на обсуждении собрания Иссакуа, мы достигли консенсус для продолжения * с подходом - "Контейнеры неполных Типы", но ограничивайте область
std::vector,std::listиstd::forward_list, как первый шаг.
А что касается изменений в стандарте (акцент мой):
Неполный тип
Tможет использоваться при создании экземпляраvector, если распределитель удовлетворяет требованиям-комплектности распределителя (17.6.3.5.1). T должно быть полным до того, как какой-либо член специализация вектора.
Итак, у вас есть это, если вы оставите по умолчанию std::allocator<T> на месте при создании экземпляра std::vector<T, Allocator>, тогда он всегда будет работать с неполным типом T в соответствии с документом; в противном случае это зависит от того, что ваш Allocator является исполняемым с неполным типом T.
A - неполный тип, верно? Если бы был вектор A * s, я бы понял. Но здесь я не понимаю, как это работает. Кажется, это рекурсивное определение.
Там нет рекурсии. В чрезвычайно упрощенной форме он похож на:
class A{
A* subAs;
};
Технически, кроме size, capacity и, возможно, allocator, std::vector нужно только удерживать указатель на динамический массив A, который управляет через его распределитель. (И размер указателя известен во время компиляции.)
Итак, реализация может выглядеть так:
namespace std{
template<typename T, typename Allocator = std::allocator<T>>
class vector{
....
std::size_t m_capacity;
std::size_t m_size;
Allocator m_allocator;
T* m_data;
};
}