Почему на земле работает следующий фрагмент кода?
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;
};
}