A alocação dinâmica é necessária apenas quando a vida útil do objeto deve ser diferente do escopo em que é criado (isso também é válido para tornar o escopo menor e maior) e você tem um motivo específico para armazená-lo por valor. trabalhos.
Por exemplo:
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 do C ++ 11, temos que std::unique_ptr
lidar com a memória alocada, que contém a propriedade da memória alocada.std::shared_ptr
foi criado para quando você precisa compartilhar a propriedade. (você precisará disso menos do que o esperado em um bom programa)
Criar uma instância se torna 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
O C ++ 17 também adiciona, o std::optional
que pode impedir que você exija alocações de memória
auto optInstance = std::optional<Class>{};
if (condition)
optInstance = Class{};
Assim que 'instância' sai do escopo, a memória é limpa. Transferir propriedade também é 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)
Então, quando você ainda precisa new
? Quase nunca a partir do C ++ 11. A maioria dos que você usa std::make_unique
até chegar a um ponto em que atinge uma API que transfere a propriedade por meio de ponteiros brutos.
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
No C ++ 98/03, você precisa fazer o gerenciamento manual de memória. Se você estiver nesse caso, tente atualizar para uma versão mais recente do padrão. Se você está preso:
auto instance = new Class(); // Allocate memory
delete instance; // Deallocate
auto instances = new Class[42](); // Allocate memory
delete[] instances; // Deallocate
Certifique-se de rastrear a propriedade corretamente para não haver vazamentos de memória! A semântica de movimento também não funciona.
Então, quando precisamos de malloc em C ++? O único motivo válido seria alocar memória e inicializá-la mais tarde através do posicionamento 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
Mesmo assim, o acima exposto é válido, isso também pode ser feito através de um novo operador. std::vector
é um bom exemplo disso.
Finalmente, ainda temos o elefante na sala: C
. Se você precisar trabalhar com uma biblioteca C em que a memória seja alocada no código C ++ e liberada no código C (ou vice-versa), você será forçado a usar o malloc / free.
Se você estiver nesse caso, esqueça as funções virtuais, funções membro, classes ... Somente estruturas com PODs nele são permitidas.
Algumas exceções às regras:
- Você está escrevendo uma biblioteca padrão com estruturas de dados avançadas onde o malloc é apropriado
- Você precisa alocar grandes quantidades de memória (na cópia de memória de um arquivo de 10 GB?)
- Você tem ferramentas impedindo o uso de certas construções
- Você precisa armazenar um tipo incompleto