В: Мое понимание верно?
A: Ваше понимание частично верно.
- p1 и p2 созданыв стеке, используя конструктор по умолчанию без аргументов, который вы определили.
- Распределитель по умолчанию может использоваться для выделения большего объема памяти для p1 и p2 при вызове push_back (), но это не всегда происходит.Тем не менее, он никогда не создаст конструкцию по умолчанию для нового экземпляра Point.
В: Если новые объекты Point создаются Allocator, почему я вижу только две строки «Созданных точек»?
A: Новые объекты не создаются распределителем - распределитель только выделяет больше памяти, , если необходимо .Объекты, которые вы вставляете в вектор, создаются копией.Поскольку вы не создали конструктор копирования, компилятор сгенерировал его для вас.
В: Как Allocator присваивает исходные значения полям x, y вновь создаваемых объектов?Использует ли он необработанную копию памяти?
A: Как указано в предыдущем вопросе, распределитель только выделяет память и не создает и не уничтожает объекты.Поведение копирования полей выполняется конструктором копирования, который вызывается при выполнении push_back
.Автоматически сгенерированный конструктор копирования выполнит построение копии каждого члена класса для каждого члена.В вашем случае x
и y
являются примитивными типами, поэтому они будут просто скопированы в необработанную память.Если бы члены были сложными объектами, их конструкторы копирования были бы вызваны.
Q: Является ли совместно используемый указатель рекомендуемым способом возврата вектора из метода?
A: Это будет зависеть от вашего варианта использования и основано на мнении.Мой личный совет, и это для всех видов объектов:
- Если ваши варианты использования позволяют это, верните по значению (то есть
std::vector<Point> getPoints()
) - Если вам нужнодинамически распределенное хранилище, или объект, который вы хотите вернуть, может быть ничем, потому что конструкция не удалась, вернуть на
std::unique_ptr
.Это относится практически ко всем фабричным функциям, которые вы, возможно, захотите создать.Даже если вы позже захотите поделиться владельцем (см. Пункт 3), вы можете создать shared_ptr, перейдя от unique_ptr (std::shared_ptr<T> shared = std::move(unique)
); - Избегайте использования
shared_ptr
, если вам действительно не нужен общий право собственности на птр.shared_ptr
сложнее рассуждать, может создавать трудные для отладки циклы, приводящие к утечкам памяти, и тяжелее с точки зрения производительности (из-за атомарных операций, связанных с их повторным подсчетом и дополнительной выделенной памятью для блока управления).Если вы думаете, что вам нужен shared_ptr
, пересмотрите свой дизайн и подумайте, можете ли вы использовать вместо него unique_ptr
.
Как это работает:
Внутренне, std ::Vector использует память, выделенную с помощью распределителя по умолчанию (или пользовательского, если он был предоставлен) в куче.Это распределение происходит за кулисами и не зависит от размера вектора и от количества элементов в векторе (но всегда> = size()
).Вы можете узнать, на сколько элементов вектор выделил память, используя функцию capacity()
.Когда вы вызываете push_back()
, что происходит:
- Если имеется достаточно места (как определено
capacity()
) для хранения еще одного элемента, аргумент, который вы передали push_back, будет copyпостроен , с использованием конструктора копирования, если используется вариант push_back( const T& value )
, или перемещен из, если используется push_back( T&& value )
, с помощью конструктора перемещения. - Если памяти больше нет (т. Е. Новый размер ()> емкость), выделяется больше памяти, которой будет достаточно для хранения новых элементов.Сколько памяти будет выделено, определяется реализацией.Обычный шаблон заключается в удвоении объема емкости, который вектор имел ранее, до порогового значения, после чего память выделяется в сегментах.Вы можете использовать
reserve()
перед вставкой элементов, чтобы убедиться, что ваш вектор будет иметь достаточную емкость, чтобы вместить как минимум столько же элементов без новых выделений.После выделения новой памяти вектор перераспределяет все существующие элементы в новое хранилище, либо копируя их, либо перемещая их, если они не вставляются при копировании.Это перераспределение сделает недействительными все итераторы и ссылки на элементы в векторе (предостережение: правила, когда именно копирование и перемещение будут использоваться, когда перераспределение немного сложнее, но это общий случай)