std :: vector (ab) использует автомат c хранилище - PullRequest
46 голосов
/ 06 января 2020

Рассмотрим следующий фрагмент:

#include <array>
int main() {
  using huge_type = std::array<char, 20*1024*1024>;
  huge_type t;
}

Очевидно, что на большинстве платформ он будет иметь sh, поскольку размер стека по умолчанию обычно меньше 20 МБ.

Теперь рассмотрим следующее код:

#include <array>
#include <vector>

int main() {
  using huge_type = std::array<char, 20*1024*1024>;
  std::vector<huge_type> v(1);
}

Удивительно, но и вылетает! Трассировка (с одной из последних версий libstdc ++) приводит к файлу include/bits/stl_uninitialized.h, где мы можем видеть следующие строки:

typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
std::fill(__first, __last, _ValueType());

Конструктор vector с изменяющим размером должен инициализировать элементы по умолчанию, и это как это реализовано. Очевидно, что _ValueType() временно разрушает стек.

Вопрос в том, является ли это соответствующей реализацией. Если да, то это на самом деле означает, что использование вектора огромных типов весьма ограничено, не так ли?

Ответы [ 3 ]

19 голосов
/ 06 января 2020

Нет ограничений на количество автоматических c хранилищ, используемых любым стандартным API.

Всем им может потребоваться 12 терабайт стекового пространства.

Однако этот API требует только Cpp17DefaultInsertable и ваша реализация создает дополнительный экземпляр над тем, что требуется конструктору. Если это не скрыто за обнаружением объекта, который легко можно копировать и копировать, эта реализация выглядит незаконной.

9 голосов
/ 06 января 2020
huge_type t;

Очевидно, что на большинстве платформ это будет sh ...

Я оспариваю предположение о «большинстве». Поскольку память огромного объекта никогда не используется, компилятор может полностью ее игнорировать и никогда не выделять память, в этом случае не будет cra sh.

Вопрос в том, соответствует ли он реализация.

Стандарт C ++ не ограничивает использование стека и даже не признает существование стека. Итак, да, это соответствует стандарту. Но можно подумать, что это проблема качества реализации.

На самом деле это означает, что использование вектора огромных типов весьма ограничено, не так ли?

Это похоже на случай с libstdc ++. Cra sh не был воспроизведен с libc ++ (с использованием clang), поэтому кажется, что это не ограничение в языке, а скорее только в этой конкретной реализации.

5 голосов
/ 07 января 2020

Я не адвокат по языкам и не эксперт по стандарту C ++, но cppreference.com говорит:

explicit vector( size_type count, const Allocator& alloc = Allocator() );

Создает контейнер с количеством вставленных по умолчанию экземпляров Т. Копии не делаются.

Возможно, я неправильно понимаю "вставлено по умолчанию", но я ожидаю:

std::vector<huge_type> v(1);

будет эквивалентно

std::vector<huge_type> v;
v.emplace_back();

Последняя версия не должна создавать стековую копию, а должна создавать тип огромный_прямой непосредственно в динамической памяти c вектора.

Я не могу достоверно сказать, что то, что вы видите, не соответствует , но это, конечно, не то, что я ожидал бы от качественной реализации.

...