Compartilhar via


Vida útil do objeto e o gerenciamento de recursos (C++ moderno)

Ao contrário das linguagens gerenciadas, C++ não tem coleta de lixo (GC), que automaticamente libera recursos de memória não-mais-usada como um programa é executado.No C++, gerenciamento de recursos está diretamente relacionado à vida útil do objeto.Este documento descreve os fatores que afetam a vida útil do objeto em C++ e como gerenciá-lo.

C++ não tem GC principalmente porque ele não manipular recursos de memória não.Somente deterministas destruidores como os do C++ podem manipular recursos de memória e memória não igualmente.GC também tem outros problemas, como a maior sobrecarga de memória e consumo de CPU e localidade.Mas universality é um problema fundamental não pode ser atenuado através de otimizações inteligentes.

Conceitos

Uma coisa importante no gerenciamento da vida útil do objeto é o encapsulamento — quem está usando um objeto não precisa saber o que possui recursos que o objeto ou como eliminá-los ou até mesmo se ele possui todos os recursos em todos os.Ele tem apenas destruir o objeto.Linguagem C++ core é projetada para garantir que os objetos são destruídos no horário correto, ou seja, como os blocos são saídos, na ordem inversa de construção.Quando um objeto é destruído, suas bases e membros são destruídos em uma ordem específica.O idioma automaticamente destrói objetos, a menos que você faça coisas especiais como alocação de heap ou posicionamento novo.Por exemplo, ponteiros inteligentes como unique_ptr e shared_ptr, e como contêineres STL Standard Template Library () vector, encapsular new/delete e new[]/delete[] em objetos, que têm destruidores.É por isso que é tão importante usar ponteiros inteligentes e contêineres STL.

Outro conceito importante no gerenciamento da vida útil: destruidores.Destruidores encapsulam a liberação de recursos.(Comumente usado mnemônico é RRID, recurso de versão é destruição). Um recurso é algo que obter do "sistema" e que dar mais tarde.A memória é o recurso mais comum, mas também há arquivos, soquetes, texturas e outros recursos de memória não. "Proprietário"um recurso significa que você pode usá-lo quando necessário, mas você também deve liberá-lo quando você terminar com ele.Quando um objeto é destruído, seu destruidor libera os recursos que ele pertence.

O conceito final é DAG (direcionado acíclica gráfico).A estrutura de propriedade em um programa constitui um DAG.Nenhum objeto pode possuir a mesmo — que não só é impossível, mas também inerentemente sem sentido.Mas dois objetos podem compartilhar a propriedade do terceiro objeto.Vários tipos de links são possíveis em um DAG como este: A é membro B (B possui um), lojas c um vector<D> (C possui cada elemento D), lojas e uma shared_ptr<F> (E compartilha apropriar F, possivelmente com outros objetos), e assim por diante.Desde que não há nenhum ciclo e todos os links de DAG é representado por um objeto que tenha um destruidor (em vez de um ponteiro bruto, identificador ou outro mecanismo) e vazamentos de recurso são impossíveis porque a linguagem impede-los.Recursos são liberados imediatamente após eles não são mais necessários, sem um coletor de lixo em execução.A vida útil do controle é livre de sobrecarga de pilha escopo, bases, membros e casos relacionados e barato para shared_ptr.

Hh438473.collapse_all(pt-br,VS.110).gifTempo de vida de heap

Tempo de vida do objeto de pilha, use ponteiros inteligentes.Use shared_ptr e make_shared como o alocador e ponteiro padrão.Use weak_ptr para quebrar ciclos, do cache e observar objetos sem afetar ou assumindo nada sobre suas vidas úteis.

void func() {

auto p = make_shared<widget>(); // no leak, and exception safe
...
p->draw(); 

} // no delete required, out-of-scope triggers smart pointer destructor

Use unique_ptr de propriedade exclusiva, por exemplo, o pimpl idioma.(See Pimpl para o encapsulamento de tempo de compilação (C++ moderno).) Fazer uma unique_ptr o destino principal de explícitos new expressões.

unique_ptr<widget> p(new widget());

Você pode usar indicadores brutos não propriedade e Observação.Um ponteiro não proprietário pode dangle, mas não podem vazar.

class node {
  ...
  vector<unique_ptr<node>> children; // node owns children
  node* parent; // node observes parent, which is not a concern
  ...
};
node::node() : parent(...) { children.emplace_back(new node(...) ); }

Quando a otimização do desempenho é necessária, talvez você precise usar well-encapsulated proprietário ponteiros e chamadas explícitas para excluir.Um exemplo é quando você implementar sua própria estrutura de dados de baixo nível.

Hh438473.collapse_all(pt-br,VS.110).gifTempo de vida de pilha

No C++ moderno, escopo baseado em pilha é uma maneira eficiente para escrever código robusto porque combina automático vida útil da pilha e o tempo de vida de membro de dados com alta eficiência — controle de tempo de vida é essencialmente livre de sobrecarga.Vida útil do objeto heap requer gerenciamento manual diligent e pode ser a fonte de perdas de recursos e ineficiência, especialmente quando você estiver trabalhando com indicadores brutos.Considere este código, demonstra o escopo de pilha:

class widget {
private:
  gadget g;   // lifetime automatically tied to enclosing object
public:
  void draw();
};

void functionUsingWidget () {
  widget w;   // lifetime automatically tied to enclosing scope
              // constructs w, including the w.g gadget member
  …
  w.draw();
  …
} // automatic destruction and deallocation for w and w.g
  // automatic exception safety, 
  // as if "finally { w.dispose(); w.g.dispose(); }"

Use com moderação vida estática (global static, estática local função) porque podem surgir problemas.O que acontece quando o construtor de um objeto global lança uma exceção?Normalmente, as falhas de aplicativo de forma que pode ser difícil de depurar.Ordem de construção é problemática para objetos de vida estática e não é seguro de simultaneidade.É não apenas um problema de construção do objeto ordem de destruição pode ser complexo, especialmente onde o polimorfismo está envolvido.Mesmo se o objeto ou variável não é polimórfico e não tiver pedidos construção/destruição complexa, ainda há o problema de simultaneidade de thread-safe.Um aplicativo multithread com segurança não pode modificar os dados em objetos estáticos sem a necessidade de armazenamento thread local, bloqueios de recursos e outras precauções especiais.

Consulte também

Outros recursos

Guia de programação C++ moderno

Referência de linguagem C++

Referência da biblioteca C++ padrão