As pessoas que estão acostumadas a usar as linguagens coletadas para o lixo geralmente têm medo do gerenciamento de memória do C ++. Existem ferramentas, como auto_ptr
e shared_ptr
que manipularão muitas das tarefas de gerenciamento de memória para você. Muitas bibliotecas C ++ são anteriores a essas ferramentas e têm seu próprio modo de lidar com as tarefas de gerenciamento de memória.
Quanto tempo você gasta em tarefas de gerenciamento de memória?
Suspeito que ele seja altamente dependente do conjunto de bibliotecas que você usa; portanto, diga a quais perguntas sua resposta se aplica e se a tornam melhor ou pior.
Respostas:
O C ++ moderno faz com que você não se preocupe com o gerenciamento de memória até que seja necessário, ou seja, até que você precise organizar sua memória manualmente, principalmente para fins de otimização ou se o contexto forçar você a fazê-lo (pense em hardware com grandes restrições). Eu escrevi jogos inteiros sem manipular a memória bruta, apenas me preocupando com o uso de contêineres que são a ferramenta certa para o trabalho, como em qualquer idioma.
Portanto, depende do projeto, mas na maioria das vezes não é com o gerenciamento de memória que você precisa lidar, mas apenas com o objeto durante a vida útil. Isso é resolvido usando ponteiros inteligentes , que é uma das ferramentas idiomáticas do C ++ resultantes do RAII .
Depois de entender o RAII , o gerenciamento de memória não será um problema.
Então, quando você precisar acessar a memória bruta, fará isso em código muito específico, localizado e identificável, como nas implementações de objetos de pool, e não "em todos os lugares".
Fora desse tipo de código, você não precisará manipular a memória, apenas o tempo de vida dos objetos.
A parte "difícil" é entender o RAII.
fonte
delete
manualmente, a menos que você tenha uma implementação de merda.return
)O gerenciamento de memória é usado para assustar as crianças, mas é apenas um tipo de recurso que um programador precisa cuidar. Pense em identificadores de arquivo, conexões de rede e outros recursos que você obtém do SO.
Os idiomas que oferecem suporte à coleta de lixo geralmente não apenas ignoram a existência desses recursos, mas também tornam mais difícil lidar com eles adequadamente, não fornecendo um destruidor.
Portanto, resumindo, eu sugeriria que não se gaste muito tempo se desenvolvendo em C ++ se preocupando com o gerenciamento de memória. Como a resposta de klaim indica, depois de controlar o RAII, o resto é apenas reflexo.
fonte
finalize
construção. No entanto, você não sabe quando será chamado. Vai demorar para você ficar sem soquetes ou objetos WebResponse? Você encontrará muitos artigos que lhe dizem que não deve confiarfinalize
- por um bom motivo.Praticamente nenhum. Mesmo em tecnologias antigas como COM, você pode escrever deleters personalizados para os ponteiros padrão que os converterão em um período muito curto. Por exemplo,
std::unique_ptr
pode ser convertido para manter exclusivamente uma referência COM com cinco linhas de um deleter personalizado. Mesmo se você precisar escrever manualmente seu próprio manipulador de recursos, a prevalência de conhecimento como SRP e copiar e trocar torna relativamente fácil escrever uma classe de gerenciamento de recursos para usar sempre mais.A realidade é que todos os itens compartilhados, únicos e sem propriedade são fornecidos com o compilador C ++ 11, e você só precisa escrever pequenos adaptadores para fazê-los funcionar mesmo com o código antigo.
fonte
Quando eu era um programador de C ++ (há muito tempo), gastei muito tempo me preocupando com os erros de gerenciamento de memória ao tentar corrigir os erros de reprodução .
Com o modem C ++, o gerenciamento de memória é muito menos problemático, mas você pode confiar em todos os membros de uma grande equipe para acertar. Qual é o custo / tempo de:
Portanto, não é apenas o tempo gasto “ fazendo ”, é mais um problema em grandes projetos.
fonte
Eu uso muito as bibliotecas boost e TR1, e elas tornam o gerenciamento de memória no sentido estrito (novo / excluir) um problema. Por outro lado, a alocação de memória em C ++ não é barata e é preciso prestar atenção ao local em que esses ponteiros compartilhados sofisticados são criados. Você acaba usando muito os espaços de trabalho ou trabalhando com a memória baseada em pilha. Em geral, eu diria que é principalmente um problema de design, não um problema de implementação.
fonte
quanto tempo leva como cliente? muito pouco, quando você pegar o jeito. quando um contêiner gerencia a vida útil e as referências, é realmente muito fácil. imo, é muito mais simples que a contagem manual de referências e é praticamente transparente se você considerar o contêiner usado como documentação que o compilador convenientemente impede que você realize transferências de propriedade inválidas em um sistema typesafe bem projetado.
Na maioria das vezes, gasto (como cliente) é gasto contendo tipos de outras APIs, para que funcionem bem no contexto de seus programas. exemplo: este é o meu recipiente ThirdPartyFont, e suporta esses recursos, e destruição implementos desta maneira, e contagem de referência desta maneira, e copiar este caminho, e ... . Muitas dessas construções precisam estar no lugar, e geralmente é o lugar lógico para colocá-las. se você deseja incluir isso com o tempo ou não, depende da sua definição (a implementação precisa existir ao interagir com essas APIs, afinal, certo?).
depois disso, você precisará levar em consideração a memória e a propriedade. em um sistema de nível inferior, isso é bom e necessário, mas pode levar algum tempo e andaimes para implementar como você deve mudar as coisas. eu não vejo isso como uma dor, uma vez que este é um requisito de um sistema de nível inferior. propriedade, controle e responsabilidade são evidentes.
para que possamos direcionar isso para apis baseadas em c que usam tipos opacos: nossos contêineres nos permitem abstrair todos os pequenos detalhes de implementação de gerenciamento da vida útil e cópia desses tipos opacos, o que torna o gerenciamento de recursos muito simples e economiza tempo, defeitos, e reduz implementações.
é realmente muito simples usá-las - o problema (vindo do GC) é que você precisa considerar a vida útil dos seus recursos. se você errar, pode demorar muito tempo para resolver. aprender e integrar o gerenciamento explícito da vida é compreensivelmente complexo em comparação (não para todas as pessoas) - esse é o verdadeiro obstáculo. quando você estiver confortável controlando as vidas úteis e usando boas soluções, será realmente muito fácil gerenciar a vida útil dos recursos. não é uma parte significativa do meu dia (a menos que um bug difícil tenha surgido).
se você não estiver usando contêineres (ponteiro automático / compartilhado), estará implorando por dor.
Eu implementei minhas próprias bibliotecas. leva -me tempo para implementar essas coisas, mas a maioria das pessoas reutilizar (que geralmente é uma boa idéia).
fonte
Você quer dizer manualmente ter que liberar memória, fechar arquivos, coisas desse tipo? Nesse caso, eu diria o mínimo e normalmente menos do que a maioria dos outros idiomas que usei, especialmente se generalizarmos isso não apenas para "gerenciamento de memória", mas "gerenciamento de recursos". Nesse sentido, acho que o C ++ requer menos gerenciamento manual de recursos do que, digamos, Java ou C #.
É principalmente devido a destruidores que automatizam a destruição do recurso (memória ou não). Normalmente, a única vez que tenho que liberar / destruir um recurso manualmente em C ++ é se estou implementando uma estrutura de dados no nível vlow (algo que a maioria das pessoas não precisa fazer) ou usando uma API C, onde passo apenas um pouco de tempo agrupando o recurso C que precisa ser liberado / destruído / fechado manualmente em um wrapper C ++ em conformidade com RAII.
É claro que se um usuário solicitar o fechamento de uma imagem em um software de edição de imagens, eu tenho que remover a imagem de uma coleção ou algo assim. Mas espero que isso não conte como gerenciamento de "memória" ou "recurso" de um tipo que importa nesse contexto, pois isso é praticamente necessário em qualquer idioma, se você quiser liberar a memória associada a essa imagem naquele momento. Mas, novamente, tudo o que você precisa fazer é remover a imagem da coleção e o destruidor de imagens cuidará do resto.
Enquanto isso, se eu comparar, digamos, Java ou C #, você geralmente encontrará pessoas que precisam fechar arquivos manualmente, desconectar soquetes manualmente, definir referências de objetos como nulas para permitir que sejam coletadas como lixo, etc. Há muito mais memória manual e gerenciamento de recursos nesses idiomas, se você me perguntar. No C ++, muitas vezes você nem precisa de
unlock
um mutex manualmente, pois o armário do mutex fará isso automaticamente quando o mutex estiver fora do escopo. Por exemplo, você nunca deve fazer coisas como esta em C ++:Não é necessário fazer coisas como fechar arquivos manualmente em C ++. Eles acabam se fechando automaticamente no instante em que ficam fora do escopo, como resultado ou em caminhos de execução normais ou excepcionais. Coisa semelhante para recursos relacionados à memória, como
std::vector
. Esse código, comofile.Close()
acima, muitas vezes seria desaprovado, pois, especialmente no contexto de umfinally
bloco, que sugere que o recurso local precisa ser liberado manualmente quando toda a mentalidade em torno do C ++ é automatizá-lo.Em termos de gerenciamento manual de memória, eu diria que C requer o máximo, Java / C # uma quantidade média e C ++ o mínimo entre esses. Há muitas razões para ser um pouco tímido em usar C ++, pois é uma linguagem muito difícil de dominar, mas o gerenciamento de memória não deve ser um deles. Pelo contrário, acho que é uma das línguas mais fáceis por aí neste aspecto.
É claro que o C ++ permite que você comece a alocar manualmente a memória e a invocar
operator delete/delete[]
para liberar memória manualmente. Também permite usar funções C comomalloc
efree
. Mas essas são práticas de codificação no estilo antigo que eu acho que se tornaram obsoletas muito antes das pessoas darem crédito, já que Stroustrup estava defendendo a RAII antes mesmo de cunhar o termo desde muito cedo. Portanto, nem acho justo dizer que "C ++ moderno" automatiza o gerenciamento de recursos, porque esse deveria ser o objetivo o tempo todo. Praticamente não é possível obter segurança de exceção. Só que muitos desenvolvedores mal orientados durante o início dos anos 90 tentaram usar C ++ como C com objetos, geralmente ignorando completamente o tratamento de exceções, e nunca era para ser usado dessa maneira. Se você usa C ++ da maneira que ele sempre pretendia ser usado, o gerenciamento de memória é totalmente automatizado e, geralmente, não é algo com o qual você tenha que lidar manualmente (ou deveria estar lidando com) muito.fonte
Depende dos líderes técnicos sênior da equipe. Em algumas empresas (incluindo a minha), não existe um conceito chamado smart poiner. É considerado chique. Portanto, as pessoas simplesmente excluem todos os lugares e há uma unidade para correção de vazamento de memória a cada 2 meses. Nova onda de instruções de exclusão chega a todos os lugares. Então, depende da empresa e do tipo de pessoas que trabalham lá.
fonte
auto_ptr
e de amigos?