La asignación dinámica solo se requiere cuando el tiempo de vida del objeto debe ser diferente del alcance en el que se crea (esto también es válido para hacer que el alcance sea más pequeño y más grande) y tiene una razón específica donde almacenarlo por valor no trabajo.
Por ejemplo:
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);
A partir de C ++ 11, tenemos que std::unique_ptr
lidiar con la memoria asignada, que contiene la propiedad de la memoria asignada.std::shared_ptr
fue creado para cuando tienes que compartir la propiedad. (necesitará esto menos de lo que esperaría en un buen programa)
Crear una instancia se vuelve realmente fácil:
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 también agrega lo std::optional
que puede evitar que requiera asignaciones de memoria
auto optInstance = std::optional<Class>{};
if (condition)
optInstance = Class{};
Tan pronto como 'instancia' se sale del alcance, la memoria se limpia. Transferir la propiedad también es fácil:
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)
Entonces, ¿cuándo todavía lo necesitas new
? Casi nunca desde C ++ 11 en adelante. La mayoría de las que usa std::make_unique
hasta que llega a un punto en el que alcanza una API que transfiere la propiedad a través de punteros sin procesar.
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
En C ++ 98/03, debe hacer una gestión manual de la memoria. Si se encuentra en este caso, intente actualizar a una versión más reciente del estándar. Si estás atrapado:
auto instance = new Class(); // Allocate memory
delete instance; // Deallocate
auto instances = new Class[42](); // Allocate memory
delete[] instances; // Deallocate
¡Asegúrese de rastrear la propiedad correctamente para no tener pérdidas de memoria! La semántica de movimiento tampoco funciona todavía.
Entonces, ¿cuándo necesitamos malloc en C ++? La única razón válida sería asignar memoria e inicializarla más tarde mediante la colocación de 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
Aunque lo anterior es válido, esto también se puede hacer a través de un nuevo operador. std::vector
Es un buen ejemplo de esto.
Por último, todavía tenemos el elefante en la habitación: C
. Si tiene que trabajar con una biblioteca C donde la memoria se asigna en el código C ++ y se libera en el código C (o al revés), se ve obligado a usar malloc / free.
Si estás en este caso, olvídate de las funciones virtuales, las funciones miembro, las clases ... Solo se permiten estructuras con PODs.
Algunas excepciones a las reglas:
- Está escribiendo una biblioteca estándar con estructuras de datos avanzadas donde malloc es apropiado
- Tiene que asignar grandes cantidades de memoria (¿En la copia de memoria de un archivo de 10GB?)
- Tiene herramientas que le impiden usar ciertas construcciones
- Necesitas almacenar un tipo incompleto