Compartilhar via


Ponteiros inteligentes (guia de programação do C++ moderno)

Na programação do C++ moderna, inclui a biblioteca padrão ponteiros inteligentes, que são usados para ajudar a garantir que os programas são livres de memória e recursos vazamentos de exceção segura.

Usos para ponteiros inteligentes

Ponteiros inteligentes são definidos na std namespace na <memory> arquivo de cabeçalho.Eles são cruciais para o RAII ou Recurso de aquisição É Initialialization idioma de programação.O objetivo principal deste idioma é garantir que a aquisição do recurso ocorre ao mesmo tempo que o objeto é inicializado para que todos os recursos do objeto são criados e preparados em uma linha de código.Em termos práticos, o princípio principal de RAII é dar a propriedade de qualquer recurso alocado de heap — por exemplo, a memória alocada dinamicamente ou identificadores de objeto do sistema — um objeto alocado na pilha cujo destruidor contém o código para excluir ou liberar o recurso e também qualquer código de limpeza associado.

Na maioria dos casos, quando você inicializar um identificador de ponteiro ou recurso bruto para apontar para um recurso real, passe o ponteiro para um ponteiro inteligente imediatamente.No C++ moderno, indicadores brutos são usados somente em blocos de código pequeno de funções limitadas de escopo, loops ou auxiliar onde o desempenho é crítico e não há nenhuma chance de confusão sobre a propriedade.

O exemplo a seguir compara uma declaração de ponteiro não processado para uma declaração de ponteiro inteligente.

void UseRawPointer()
{
    // Using a raw pointer -- not recommended.
    Song* pSong = new Song(L"Nothing on You", L"Bruno Mars"); 

    // Use pSong...

    // Don't forget to delete!
    delete pSong;   
}


void UseSmartPointer()
{
    // Declare a smart pointer on stack and pass it the raw pointer.
    unique_ptr<Song> song2(new Song(L"Nothing on You", L"Bruno Mars"));

    // Use song2...
    wstring s = song2->duration_;
    //...

} // song2 is deleted automatically here.

Como mostrado no exemplo, um ponteiro inteligente é um modelo de classe declarar na pilha e inicializar usando um ponteiro bruto que aponta para um objeto alocado de heap.Depois de inicializar o ponteiro inteligente, ele possui o ponteiro bruto.Isso significa que o ponteiro inteligente é responsável por excluir a memória que o ponteiro raw especifica.O destruidor de ponteiro inteligente contém a chamada para excluir e porque o ponteiro inteligente é declarado na pilha, do destruidor é chamado quando o ponteiro inteligente sai do escopo, mesmo se uma exceção é lançada em algum lugar ainda mais na pilha.

Acessar o ponteiro encapsulado usando operadores de ponteiro familiar, -> e *, que a classe de ponteiro inteligente sobrecargas para retornar o ponteiro bruto encapsulado.

O idioma de ponteiro inteligente do C++ é semelhante a criação de objetos em linguagens como C#: criar o objeto e deixe o sistema cuidam de excluí-lo no momento correto.A diferença é que nenhum separado coletor de lixo é executado em segundo plano; a memória é gerenciada através do C++ padrão regras de escopo para que o ambiente de tempo de execução é mais rápida e eficiente.

Observação importanteImportante

Sempre crie ponteiros inteligentes em uma linha separada do código, nunca em uma lista de parâmetro, para que um vazamento de recursos sutis não ocorre devido a certas regras de alocação de lista de parâmetro.

A exemplo a seguir mostra como um unique_ptr tipo de ponteiro inteligente da biblioteca de modelo padrão pode ser usado para encapsular um ponteiro para um objeto grande.


class LargeObject
{
public:
    void DoSomething(){}
};

void ProcessLargeObject(const LargeObject& lo){}
void SmartPointerDemo()
{    
    // Create the object and pass it to a smart pointer
    std::unique_ptr<LargeObject> pLarge(new LargeObject());

    //Call a method on the object
    pLarge->DoSomething();

    // Pass a reference to a method.
    ProcessLargeObject(*pLarge);

} //pLarge is deleted automatically when function block goes out of scope.

O exemplo demonstra as seguintes etapas essenciais para o uso de ponteiros inteligentes.

  1. Declare o ponteiro inteligente como uma variável (local) automática.(Não use o new ou malloc expressão no ponteiro inteligente próprio.)

  2. No parâmetro de tipo, especifique o tipo apontado para ponteiro encapsulado.

  3. Passar um ponteiro não processado para um new-objeto ed no construtor de ponteiro inteligente.(Algumas funções do utilitário ou construtores de ponteiro inteligente feito para você.)

  4. Use o sobrecarregado -> e * operadores para acessar o objeto.

  5. Deixe o ponteiro inteligente excluir o objeto.

Ponteiros inteligentes são projetados para ser tão eficiente quanto possível, tanto em termos de memória e desempenho.Por exemplo, o membro de dados somente na unique_ptr é o ponteiro encapsulado.Isso significa que unique_ptr é exatamente o mesmo tamanho que ponteiro bytes quatro ou oito bytes.Acessando o ponteiro encapsulado usando o ponteiro inteligente sobrecarregado * e - > operadores não é significativamente mais lento do que acessar indicadores brutos diretamente.

Ponteiros inteligentes possuem suas próprias funções de membro que são acessadas usando a notação "ponto".Por exemplo, alguns ponteiros inteligentes STL tem uma função de membro reset libera a propriedade do ponteiro.Isso é útil quando você deseja liberar a memória de propriedade ponteiro inteligente antes de ponteiro inteligente sai do escopo, conforme mostrado no exemplo a seguir.

void SmartPointerDemo2()
{
    // Create the object and pass it to a smart pointer
    std::unique_ptr<LargeObject> pLarge(new LargeObject());

    //Call a method on the object
    pLarge->DoSomething();

    // Free the memory before we exit function block.
    pLarge.reset();

    // Do some other work...

}

Ponteiros inteligentes geralmente fornecem uma maneira de acessar diretamente o ponteiro bruto.Ponteiros inteligentes STL tem um get função de membro para esse fim, e CComPtr tem um público p membro da classe.Fornecendo acesso direto ao ponteiro subjacente, você pode usar o ponteiro inteligente para gerenciar a memória no seu próprio código e ainda passar o ponteiro bruto para código não aceita ponteiros inteligentes.

void SmartPointerDemo4()
{
    // Create the object and pass it to a smart pointer
    std::unique_ptr<LargeObject> pLarge(new LargeObject());

    //Call a method on the object
    pLarge->DoSomething();

    // Pass raw pointer to a legacy API
    LegacyLargeObjectFunction(pLarge.get());    
}

Tipos de ponteiros inteligentes

A seção a seguir resume os diferentes tipos de ponteiros inteligentes disponíveis no ambiente de programação do Windows e descreve quando usá-los.

  • Ponteiros inteligentes de biblioteca C++ padrão
    Use esses ponteiros inteligentes como primeira opção para encapsular os ponteiros para objetos de C++ antigos simples (POCO).

    • unique_ptr
      Permite exatamente um proprietário de ponteiro subjacente.Usar como a escolha padrão para POCO a menos que você tem certeza de que você precisa de um shared_ptr.Podem ser movidos para um novo proprietário, mas não copiados ou compartilhados.Substitui auto_ptr, que é preterido.Compare com boost::scoped_ptr.unique_ptré pequeno e eficiente; o tamanho é um ponteiro e oferece suporte a referências de rvalue para inserção rápida e a recuperação de coleções de STL.Arquivo de cabeçalho: <memory>.Para obter mais informações, consulte Como: criar e usar instâncias de unique_ptr e unique_ptr Class.

    • shared_ptr
      Contado de referência de ponteiro inteligente.Use quando você deseja atribuir um ponteiro bruto vários proprietários, por exemplo, quando você retorna uma cópia de um ponteiro de um contêiner, mas deseja manter o original.O ponteiro bruto não é excluído até que todos shared_ptr proprietários ficaram fora do escopo ou caso contrário ter desistido de propriedade.O tamanho é de dois ponteiros; uma para o objeto e uma para o bloco de controle compartilhado que contém a contagem de referência.Arquivo de cabeçalho: <memory>.Para obter mais informações, consulte Como: criar e usar instâncias shared_ptr e shared_ptr Class.

    • weak_ptr
      Casos especiais ponteiro inteligente para uso em conjunto com shared_ptr.A weak_ptr fornece acesso a um objeto que pertence a um ou mais shared_ptr instâncias, mas não participa de contagem de referência.Use quando você deseja observar um objeto, mas não precisam permanecer ativo.Necessária em alguns casos para quebrar referências circulares entre shared_ptr instâncias.Arquivo de cabeçalho: <memory>.Para obter mais informações, consulte Como: criar e usar instâncias weak_ptr e weak_ptr Class.

  • Ponteiros inteligentes para objetos COM (programação do Windows clássico)
    Ao trabalhar com objetos COM, dispor os ponteiros de interface em um tipo de ponteiro inteligente apropriado.Active Template Library (ATL) define vários ponteiros inteligentes para várias finalidades.Você também pode usar o _com_ptr_t tipo de ponteiro inteligente, o compilador usa quando cria classes de wrapper de arquivos. tlb.É a melhor opção quando você não deseja incluir arquivos de cabeçalho ATL.

  • ATL Smart ponteiros para objetos POCO
    Além das inteligentes ponteiros para objetos COM ATL também define ponteiros inteligentes e coleções de ponteiros inteligentes, simples objetos C++ antigo.Na programação clássica do Windows, esses tipos são alternativas úteis para coleções STL, especialmente quando a portabilidade do código não é necessária ou não deseja misturar modelos de programação de STL e ATL.

    • Classe CAutoPtr
      Ponteiro inteligente que reforça a propriedade exclusiva por transferência de propriedade na cópia.Comparável a preteridas std::auto_ptr classe.

    • Classe CHeapPtr
      Ponteiro inteligente para objetos que são alocados por meio de c malloc função.

    • Classe CAutoVectorPtr
      Ponteiro inteligente para matrizes que são alocadas usando new[].

    • Classe CAutoPtrArray
      Classe que encapsula uma matriz de CAutoPtr elementos.

    • Classe CAutoPtrList
      Classe que encapsula os métodos para manipular uma lista de CAutoPtr nós.

Consulte também

Outros recursos

Guia de programação C++ moderno

Referência de linguagem C++

Referência da biblioteca C++ padrão

Visão geral: Gerenciamento de memória em C++