Динамическое выделение требуется только в том случае, если время жизни объекта должно отличаться от объема, в котором он создается (это также относится к уменьшению и увеличению области), и у вас есть особая причина, по которой его следует хранить по значению не работает.
Например:
std::vector<int> *createVector(); // Bad
std::vector<int> createVector(); // Good
auto v = new std::vector<int>(); // Bad
auto result = calculate(/*optional output = */ v);
auto v = std::vector<int>(); // Good
auto result = calculate(/*optional output = */ &v);
Начиная с C ++ 11, у нас есть std::unique_ptr
для работы с выделенной памятью, которая содержит владение выделенной памятью. std::shared_ptr
был создан для случаев, когда вы должны делиться собственностью. (вам нужно это меньше, чем вы ожидаете в хорошей программе)
Создание экземпляра становится действительно простым:
auto instance = std::make_unique<Class>(/*args*/); // C++14
auto instance = std::make_unique<Class>(new Class(/*args*/)); // C++11
auto instance = std::make_unique<Class[]>(42); // C++14
auto instance = std::make_unique<Class[]>(new Class[](42)); // C++11
C ++ 17 также добавляет std::optional
, что может помешать вам выделять память
auto optInstance = std::optional<Class>{};
if (condition)
optInstance = Class{};
Как только «экземпляр» выходит из области видимости, память очищается. Передача права собственности также проста:
auto vector = std::vector<std::unique_ptr<Interface>>{};
auto instance = std::make_unique<Class>();
vector.push_back(std::move(instance)); // std::move -> transfer (most of the time)
Так, когда вам все еще нужно new
? Почти никогда не начиная с C ++ 11. Большинство из них вы используете std::make_unique
, пока не дойдете до точки, где вы нажмете API, который передает владение с помощью необработанных указателей.
auto instance = std::make_unique<Class>();
legacyFunction(instance.release()); // Ownership being transferred
auto instance = std::unique_ptr<Class>{legacyFunction()}; // Ownership being captured in unique_ptr
В C ++ 98/03 вы должны выполнять ручное управление памятью. Если вы в этом случае, попробуйте обновить до более новой версии стандарта. Если вы застряли:
auto instance = new Class(); // Allocate memory
delete instance; // Deallocate
auto instances = new Class[42](); // Allocate memory
delete[] instances; // Deallocate
Убедитесь, что вы правильно отслеживаете владельца, чтобы не было утечек памяти! Семантика перемещения также не работает.
Итак, когда нам нужен malloc в C ++? Единственная действительная причина - выделение памяти и ее инициализация позднее с помощью размещения нового.
auto instanceBlob = std::malloc(sizeof(Class)); // Allocate memory
auto instance = new(instanceBlob)Class{}; // Initialize via constructor
instance.~Class(); // Destroy via destructor
std::free(instanceBlob); // Deallocate the memory
Несмотря на то, что вышеупомянутое действительно, это можно сделать и через оператора new. std::vector
является хорошим примером для этого.
Наконец, у нас все еще есть слон в комнате: C
. Если вам приходится работать с библиотекой C, в которой память выделяется в коде C ++ и освобождается в коде C (или наоборот), вы вынуждены использовать malloc / free.
Если вы в этом случае, забудьте о виртуальных функциях, функциях-членах, классах ... Допускаются только структуры с POD.
Некоторые исключения из правил:
- Вы пишете стандартную библиотеку с продвинутыми структурами данных, для которых подходит malloc
- Вы должны выделить большие объемы памяти (в оперативной копии файла 10 ГБ?)
- У вас есть инструменты, которые не позволяют использовать определенные конструкции
- Вам необходимо хранить неполный тип