Динамическое размещение требуется только в том случае, если время жизни объекта должно отличаться от области, в которой он создается (это также относится к уменьшению и увеличению области), и у вас есть особая причина, по которой его сохранение по значению не Работа.
Например:
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
Убедитесь, что вы правильно отслеживаете владение, чтобы не было утечек памяти! Семантика Move еще не работает.
Итак, когда нам нужен 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 ГБ?)
- У вас есть инструменты, мешающие вам использовать определенные конструкции
- Вам нужно хранить неполный тип