Динамическое выделение требуется только тогда, когда время жизни объекта должно отличаться от области, в которой он создается (это также справедливо для уменьшения области действия), и у вас есть конкретная причина, по которой его сохранение по значению не Работа.
Например:
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::unique_ptr<Class>(new Class(/*args*/)); // C++11
auto instance = std::make_unique<Class[]>(42); // C++14
auto instance = std::unique_ptr<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 ++? Единственная веская причина - выделить память и инициализировать ее позже путем размещения new.
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 ГБ?)
- У вас есть инструменты, которые не позволяют использовать определенные конструкции.
- Вам нужно хранить неполный тип
person
JVApen
schedule
22.12.2018