Подтвердить что ты не робот

Разделяет ли неиспользуемый контейнер STL память?

С учетом кода:

class Foo {
  std::vector<int> items;
  std::map<int, int> dictionary;
};
  • Если ничто никогда не добавляется к вышеуказанному вектору или карте, будет ли он по-прежнему выделять блок буферной памяти? (Другими словами, распределение буфера всегда происходит во время создания контейнера или может быть отложено до тех пор, пока вызовы таких функций, как push_back?)

  • Есть ли стандарт для обработки времени первоначального размещения буфера STL-контейнера или это поведение может варьироваться между контейнерами STL и компиляторами?

Примечание. Этот вопрос не касается дополнительных байтов, которые такие контейнеры будут добавлять к размеру класса Foo.

(Связанное подмножество этого вопроса с акцентом на размер выделения Начальная емкость вектора в С++.)

4b9b3361

Ответ 1

Ссылка на С++ С С++ 17 конструктор по умолчанию noexcept, если конструкция распределителя noexcept. Так что это зависит от используемого распределителя. В VS 2015 стандартный конструктор noexcept.

Разъяснение: это означает, что если распределитель не равен noexcept, тогда не выделяется блок памяти.

И для вашего второго вопроса: та же ссылка, это O (1).

Ответ 2

Стандарт ничего не говорит об этом, но реализация, на которую я смотрел, будет делать некоторые предварительные alocations для std::vector и не будет предварительно выделять что-либо для std::map.

Это на самом деле когда-то сильно ударило меня, потому что у меня был огромный контейнер, элементы которого были миниатюры - не более 10 элементов, в большинстве записей были векторы размером 0 - вектор. По умолчанию векторная емкость в этой реализации была 32, а '32 * sizeof (vector_element) * number_of_elements оказался чрезвычайно большим.

Ответ 3

Как упоминалось ранее, это не так четко определено. Однако вы можете просто протестировать его.

Например, с gcc/linux. Сделайте простую программу, скомпилируйте ее с помощью -O0 -g и запустите ее в gdb. Тогда

break main
run
break malloc
cont

Теперь просто запустите backtrace на каждом malloc, и вы увидите динамическое распределение. С моим gcc 5.3.0 оба пустых контейнера не выделяют кучную память, это делается на первом push_back/operator[].

Конечно, вы должны использовать свой предпочтительный отладчик и разбить свою базовую функцию распределителей, если это не gdb/malloc.

Теперь, если вы думаете об этих двух случаях. Было бы целесообразно предварительно выделить память в этом случае?

std::vector<int> foo;
foo.push_back(13);

Ну, технически вы можете сохранить чек для nullptr, но с обычным способом реализации векторов в виде 3 указателей нет необходимости в дополнительной проверке.

Но рассмотрим

std::vector<int> foo;
foo.reserve(100);

В этом случае было бы вредно для производительности предустановить.

Я не могу найти аргумент для предварительного выделения для древовидной структуры, такой как карта.

Пожалуйста, помните, что это очень конкретная оптимизация. Оптимизируйте это только по уважительной причине (эталон!).

Примечание. Возможно, вы захотите ознакомиться с небольшой оптимизацией строк, очень распространенной техникой, которая связана, но отличается.

Ответ 4

  • Если ничто никогда не добавляется к вышеуказанному вектору или карте, либо по-прежнему выделяет блок памяти для потенциальных записей? (Другими словами, распределение записей всегда происходит во время создания контейнера или может быть отложено до тех пор, пока вызовы таких функций, как push_back?)

Это может случиться, да. Это фактически деталь реализации контейнера и не указана в стандарте.

  1. Есть ли стандарт для обработки времени первоначального размещения контейнера STL или это поведение может варьироваться между контейнерами STL и компиляторами?

Вы можете отложить создание, используя, например, a std::unique_ptr для членов и создать их с вызовом функции getter.