Ao contrário, você deve sempre preferir alocações de pilha, na medida em que, como regra geral, você nunca deve ter new / delete em seu código de usuário.
Como você disse, quando a variável é declarada na pilha, seu destruidor é automaticamente chamado quando sai do escopo, que é sua principal ferramenta para rastrear o tempo de vida do recurso e evitar vazamentos.
Portanto, em geral, toda vez que você precisa alocar um recurso, seja memória (chamando new), identificadores de arquivo, soquetes ou qualquer outra coisa, envolva-o em uma classe onde o construtor adquire o recurso e o destruidor o libera. Em seguida, você pode criar um objeto desse tipo na pilha e tem a garantia de que seu recurso será liberado quando sair do escopo. Dessa forma, você não precisa rastrear seus pares novos / deletar em todos os lugares para evitar vazamentos de memória.
O nome mais comum para este idioma é RAII
Observe também as classes de ponteiros inteligentes que são usadas para envolver os ponteiros resultantes nos raros casos em que você precisa alocar algo com novo fora de um objeto RAII dedicado. Em vez disso, você passa o ponteiro para um ponteiro inteligente, que então rastreia seu tempo de vida, por exemplo, por contagem de referência, e chama o destruidor quando a última referência sai do escopo. A biblioteca padrão tem std::unique_ptr
um gerenciamento simples baseado em escopo e std::shared_ptr
que faz a contagem de referência para implementar a propriedade compartilhada.
Muitos tutoriais demonstram a instanciação de objetos usando um snippet como ...
Então o que você descobriu é que a maioria dos tutoriais é uma merda. ;) A maioria dos tutoriais ensina práticas ruins de C ++, incluindo chamar new / delete para criar variáveis quando não for necessário, e dificultando o controle do tempo de vida de suas alocações.
Embora ter coisas na pilha possa ser uma vantagem em termos de alocação e liberação automática, tem algumas desvantagens.
Você pode não querer alocar objetos enormes na Pilha.
Envio dinâmico! Considere este código:
Isso imprimirá "B". Agora vamos ver o que acontece ao usar o Stack:
Isso imprimirá "A", o que pode não ser intuitivo para aqueles que estão familiarizados com Java ou outras linguagens orientadas a objetos. O motivo é que você não tem mais um ponteiro para uma instância
B
. Em vez disso, uma instância deB
é criada e copiada para aa
variável do tipoA
.Algumas coisas podem acontecer de forma não intuitiva, especialmente quando você é novo em C ++. Em C você tem suas dicas e é isso. Você sabe como usá-los e eles SEMPRE fazem o mesmo. Em C ++, esse não é o caso. Imagine o que acontece, quando você usa um neste exemplo como um argumento para um método - as coisas ficam mais complicadas e FAZ uma grande diferença se
a
é do tipoA
ouA*
ou mesmoA&
(chamada por referência). Muitas combinações são possíveis e todas se comportam de maneira diferente.fonte
Bem, a razão para usar o ponteiro seria exatamente a mesma que a razão para usar ponteiros em C alocados com malloc: se você quiser que seu objeto viva mais do que sua variável!
É ainda altamente recomendado NÃO usar o novo operador se você puder evitá-lo. Especialmente se você usar exceções. Em geral, é muito mais seguro deixar o compilador liberar seus objetos.
fonte
Já vi esse antipadrão de pessoas que não entendem muito bem o operador & address-of. Se eles precisarem chamar uma função com um ponteiro, eles sempre alocarão no heap para obter um ponteiro.
fonte
Trate a pilha como um bem importante e use-a com muito cuidado. A regra básica é usar pilha sempre que possível e usar heap sempre que não houver outra maneira. Ao alocar os objetos na pilha, você pode obter muitos benefícios, como:
(1). Você não precisa se preocupar com o desenrolamento da pilha em caso de exceções
(2). Você não precisa se preocupar com a fragmentação da memória causada pela alocação de mais espaço do que o necessário por seu gerenciador de heap.
fonte
A única razão pela qual eu me preocuparia é que Dog agora está alocado na pilha, em vez de no heap. Então, se Dog tiver megabytes de tamanho, você pode ter um problema,
Se você precisar seguir a nova rota / excluir, tome cuidado com as exceções. E por causa disso, você deve usar auto_ptr ou um dos tipos de ponteiro inteligente boost para gerenciar o tempo de vida do objeto.
fonte
Não há razão para novo (no heap) quando você pode alocar na pilha (a menos que por algum motivo você tenha uma pequena pilha e queira usar o heap.
Você pode querer considerar o uso de shared_ptr (ou uma de suas variantes) da biblioteca padrão se quiser alocar no heap. Isso cuidará da exclusão para você, uma vez que todas as referências ao shared_ptr tenham deixado de existir.
fonte
Há um motivo adicional, que ninguém mais mencionou, por que você pode escolher criar seu objeto dinamicamente. Objetos dinâmicos baseados em heap permitem que você faça uso de polimorfismo .
fonte
Eu tive o mesmo problema no Visual Studio. Você tem que usar:
yourClass-> classMethod ();
ao invés de:
yourClass.classMethod ();
fonte