Pergunta

O que é um ponteiro inteligente e quando devo usar um?

Foi útil?

Solução

Atualizar

Esta resposta é muito antigo, e assim descreve o que era 'bom' no momento, que era ponteiros inteligentes fornecidos pela biblioteca Boost. Desde C ++ 11, a biblioteca padrão forneceu suficientes tipos ponteiros inteligentes, e por isso você deve favorecer o uso de std::unique_ptr , std::shared_ptr e std::weak_ptr .

Há também std::auto_ptr . É muito parecido com um ponteiro escopo, exceto que ele também tem a capacidade "especial" perigoso para ser copiado - que também transfere inesperadamente propriedade! Ele está obsoleta nas novas normas, para que você não deve usá-lo. Use o std::unique_ptr .

std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership. 
                                 // p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.

RESPOSTA OLD

Um ponteiro inteligente é uma classe que envolve um (ou 'nua') ponteiro 'bruto' C ++, para gerir o tempo de vida do objecto a ser apontada. Não existe um único tipo de ponteiro inteligente, mas todos eles tentar abstrair um ponteiro não processado de uma forma prática.

Ponteiros inteligentes deve ser preferido sobre ponteiros crus. Se você sentir que você precisa para usar ponteiros (primeiro considerar se você realmente fazer), você normalmente quer usar um ponteiro inteligente, pois isso pode aliviar muitos dos problemas com ponteiros crus, principalmente esquecendo-se de excluir o objeto e vazamento de memória.

Com ponteiros crus, o programador tem que explicitamente destruir o objeto quando ele não é mais útil.

// Need to create the object to achieve some goal
MyObject* ptr = new MyObject(); 
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?

Um ponteiro inteligente em comparação define uma política a respeito de quando o objeto é destruído. Você ainda tem que criar o objeto, mas você não precisa mais se preocupar com a destruí-lo.

SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.

// Destruction of the object happens, depending 
// on the policy the smart pointer class uses.

// Destruction would happen even if DoSomething() 
// raises an exception

A política mais simples em uso envolve o escopo do objeto ponteiro embalagem inteligente, como implementado por boost::scoped_ptr ou std::unique_ptr .

void f()
{
    {
       std::unique_ptr<MyObject> ptr(new MyObject());
       ptr->DoSomethingUseful();
    } // ptr goes out of scope -- 
      // the MyObject is automatically destroyed.

    // ptr->Oops(); // Compile error: "ptr" not defined
                    // since it is no longer in scope.
}

Note que os casos std::unique_ptr não pode ser copiado. Isto evita que o ponteiro de várias vezes ser apagadas (incorrecta). Você pode, no entanto, passar referências a ele em torno de outras funções que você chama.

std::unique_ptrs são úteis quando você quer amarrar o tempo de vida do objeto para um bloco de código específico, ou se incorporado-lo como dados de membro dentro de outro objeto, a vida útil do que outro objeto. O objecto existe até que o bloco contendo de código é terminado, ou até que o objecto que contenha em si é destruído.

A mais complexa política ponteiro inteligente envolve contagem de referência o ponteiro. Isso permitirá que o ponteiro para ser copiado. Quando o último "referência" para o objeto é destruído, o objeto é excluído. Esta política é implementada por boost::shared_ptr e std::shared_ptr .

void f()
{
    typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
    MyObjectPtr p1; // Empty

    {
        MyObjectPtr p2(new MyObject());
        // There is now one "reference" to the created object
        p1 = p2; // Copy the pointer.
        // There are now two references to the object.
    } // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero. 
  // The object is deleted.

Referência contados ponteiros são muito úteis quando a vida do seu objeto é muito mais complicado, e não está ligada diretamente a uma determinada seção de código ou a outro objeto.

Há uma desvantagem para os ponteiros contados de referência - a possibilidade de criar uma referência pendurados:

// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!

Outra possibilidade é a criação de referências circulares:

struct Owner {
   std::shared_ptr<Owner> other;
};

std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1

// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!

Para trabalhocontornar este problema, tanto Boost e C ++ 11 ter definido uma weak_ptr para definir uma referência fraca (incontados) para um shared_ptr.

Outras dicas

Aqui está uma resposta simples para estes dias de C ++ moderno:

  • O que é um ponteiro inteligente?
    É um tipo cujos valores podem ser usados ??como ponteiros, mas que fornece a característica adicional de gerenciamento automático de memória: Quando um ponteiro inteligente não está mais em uso, a memória que aponta para é desalocada (ver também a definição mais detalhada sobre Wikipedia ).
  • Quando devo usar um?
    No código que envolve o acompanhamento da propriedade de um pedaço de memória, alocando ou de-alocação; o ponteiro inteligente, muitas vezes poupa a necessidade de fazer essas coisas explicitamente.
  • Mas qual ponteiro inteligente que eu deveria usar em qual desses casos?
    • std::unique_ptr quando você não pretende manter várias referências ao mesmo objecto. Por exemplo, usá-lo para um ponteiro para a memória que é alocada ao entrar alguma margem e de afectados a sair do escopo.
    • std::shared_ptr quando você quer se referir ao seu objeto de vários lugares -. e não quer que seu objeto seja de-alocados até que todas estas referências são eles próprios ido
    • std::weak_ptr quando você quer se referir ao seu objeto de vários lugares -. para essas referências para as quais não há problema em ignorar e deallocate (assim eles vão apenas observar o objeto desaparece quando você tenta dereference)
    • Não use o ponteiros inteligentes boost:: ou std::auto_ptr exceto em casos especiais que você pode ler sobre se você precisa.
  • Hey, eu não perguntei qual usar!
    Ah, mas você realmente queria, admiti-lo.
  • Então, quando eu deveria usar ponteiros regulares então?
    Principalmente no código que é alheio a propriedade de memória. Isso normalmente seria em funções que recebem um ponteiro de outro lugar e não alocam nem de-alocar, e não armazenam uma cópia do ponteiro que sobrevive a sua execução.

inteligente ponteiro é um ponteiro-like tipo com alguma funcionalidade adicional, por exemplo desalocação de memória automática, contagem de referência etc.

Pequenas introdução está disponível na página ponteiros inteligentes - O quê, porquê, Que .

Um dos simples tipo ponteiro inteligente é std::auto_ptr (capítulo 20.4. 5 de padrão C ++), que permite desalocar memória automaticamente quando fora do escopo e que é mais robusto do que o uso de ponteiro simples quando exceções são lançadas, embora menos flexível.

Outro tipo conveniente é boost::shared_ptr que implementa referência contando e automaticamente desaloca memória quando nenhuma referência a restos de objetos. Isso ajuda a evitar vazamentos de memória e é fácil de usar para implementar RAII .

Assunto é coberto em profundidade no livro "C ++ Templates: The Complete Guide", de David Vandevoorde , Nicolai M. Josuttis , capítulo Capítulo 20. ponteiros inteligentes. Alguns tópicos abordados:

  • Proteção contra Exceções
  • Os titulares, (note, std :: auto_ptr é a implementação de tal tipo de ponteiro inteligente)
  • Resource Acquisition Is Initialization (Este é frequentemente utilizado para a gestão de recursos exceção-safe em C ++)
  • Limitações Titular
  • contagem de referência
  • Concurrent Contador Acesso
  • Destruição e Desalocação

As definições fornecidas por Chris, Sergdev e Llyod estão corretas. Eu prefiro uma definição mais simples, porém, apenas para manter a minha vida simples: Um ponteiro inteligente é simplesmente uma classe que sobrecarrega os operadores -> e *. O que significa que o seu objeto semanticamente parece com um ponteiro, mas você pode fazê-lo fazer maneira como as coisas mais frias, incluindo contagem de referência, a destruição automática etc. shared_ptr e auto_ptr são suficientes na maioria dos casos, mas vêm junto com seu próprio conjunto de pequenas idiossincrasias.

Um ponteiro inteligente é como um ponteiro normal (digitado), como "char *", exceto quando o ponteiro em si sai do escopo, em seguida, o que aponta para é excluída também. Você pode usá-lo como se fosse um ponteiro regular, usando "->", mas não se você precisa de um ponteiro real aos dados. Para isso, você pode usar "& * ptr".

É útil para:

  • Objetos que devem ser alocados com nova, mas que você gostaria de ter o mesmo tempo de vida como algo em que pilha. Se o objeto é atribuído a um ponteiro inteligente, em seguida, eles serão excluídos quando o programa termina essa função / bloco.

  • Os membros de dados de classes, de modo que quando o objeto é excluído todos os dados de propriedade é excluído, bem como, sem qualquer código especial no processo de destruição (você vai precisar para ter certeza o destruidor é virtual, que é quase sempre uma boa coisa a fazer).

Você pode não quiser usar um ponteiro inteligente quando:

  • ... o ponteiro não deve realmente possuir os dados ... ou seja, quando você estiver usando apenas os dados, mas você quer que ele sobreviver a função onde você está fazendo referência a ele.
  • ... o ponteiro inteligente não é em si vai ser destruído em algum ponto. Você não quer que ele se sentar na memória que nunca é destruída (como em um objeto que é alocada dinamicamente, mas não vai ser explicitamente excluído).
  • ... dois ponteiros inteligentes pode apontar para os mesmos dados. (Há, no entanto, os ponteiros até mesmo mais inteligentes que vai lidar com isso ... isso é chamado contagem de referência .)

Veja também:

A maioria dos tipos de ponteiros inteligentes alça eliminação do ponteiro-a objeto para você. É muito útil porque você não tem que pensar sobre a eliminação de objetos manualmente mais.

Os ponteiros inteligentes mais comumente utilizados são std::tr1::shared_ptr (ou boost::shared_ptr), e, menos comumente, std::auto_ptr. Eu recomendo o uso regular de shared_ptr.

shared_ptr é muito versátil e lida com uma grande variedade de cenários de eliminação, incluindo casos onde os objetos precisam ser "passados ??através das fronteiras DLL" (caso pesadelo comum, se diferentes libcs são usados ??entre seu código e as DLLs).

Um ponteiro inteligente é um objeto que age como um ponteiro, mas além disso, oferece controle sobre a construção, destruição, copiar, mover e dereferencing.

Pode-se implementar o próprio ponteiro inteligente, mas muitas bibliotecas também fornecer implementações de ponteiro inteligente cada um com diferentes vantagens e desvantagens.

Por exemplo, impulsionar fornece as seguintes implementações de ponteiro inteligente:

  • shared_ptr<T> é um ponteiro para T usando uma contagem de referência para determinar quando o objeto não é mais necessário.
  • scoped_ptr<T> é um ponteiro excluída automaticamente quando ele sai do escopo. Nenhuma atribuição é possível.
  • intrusive_ptr<T> é outro ponteiro contagem de referência. Ele fornece melhor desempenho do que shared_ptr, mas requer o tipo T para fornecer seu próprio mecanismo de contagem de referência.
  • weak_ptr<T> é um ponteiro fraco, trabalhando em conjunto com shared_ptr para evitar referências circulares.
  • shared_array<T> é como shared_ptr, mas para matrizes de T.
  • scoped_array<T> é como scoped_ptr, mas para matrizes de T.

Estas são apenas um descrições lineares de cada um e pode ser usado como por necessidade, para obter mais detalhes e exemplos pode-se olhar a documentação do Boost.

Além disso, biblioteca padrão do C ++ fornece três ponteiros inteligentes; std::unique_ptr para a posse única, std::shared_ptr para a posse e std::weak_ptr compartilhada. std::auto_ptr existia em C ++ 03, mas agora está obsoleta.

Aqui está o link para obter respostas semelhantes: http: //sickprogrammersarea.blogspot .in / 2014/03 / técnico-entrevista-pergunta-on-c_6.html

Um ponteiro inteligente é um objeto que age, olha e sente como um ponteiro normal, mas oferece mais funcionalidades. Em C ++, ponteiros inteligentes são implementados como classes de modelo que encapsulam um ponteiro e substituir operadores ponteiro padrão. Eles têm uma série de vantagens sobre ponteiros regulares. Eles são garantidos para ser inicializado tanto como ponteiros nulos ou apontadores para um objeto heap. Indireção através de um ponteiro nulo é verificado. Não delete é sempre necessário. Os objetos são automaticamente liberada quando o último ponteiro para eles desapareceu. Um problema significativo com esses ponteiros inteligentes é que, diferentemente ponteiros regulares, eles não respeitam herança. Ponteiros inteligentes são pouco atraentes para o código polimórfico. Dada a seguir é um exemplo para a implementação de ponteiros inteligentes.

Exemplo:

template <class X>
class smart_pointer
{
          public:
               smart_pointer();                          // makes a null pointer
               smart_pointer(const X& x)            // makes pointer to copy of x

               X& operator *( );
               const X& operator*( ) const;
               X* operator->() const;

               smart_pointer(const smart_pointer <X> &);
               const smart_pointer <X> & operator =(const smart_pointer<X>&);
               ~smart_pointer();
          private:
               //...
};

Esta classe implementar um ponteiro inteligente para um objeto do tipo X. O objeto em si está localizado na pilha. Aqui está como usá-lo:

smart_pointer <employee> p= employee("Harris",1333);

Como outros operadores sobrecarregados, p vai se comportar como um ponteiro regular,

cout<<*p;
p->raise_salary(0.5);

http://en.wikipedia.org/wiki/Smart_pointer

ciência da computação In, um ponteiro inteligente é um tipo abstrato de dados que simula um ponteiro, proporcionando características adicionais, como automático coleta de lixo ou verificação de limites. Esses recursos adicionais são destinados para reduzir os erros causados ??pelo uso indevido de ponteiros, mantendo a eficiência. ponteiros inteligentes tipicamente manter o controle de Os objetos que ponto a eles, para propósito de gerenciamento de memória. o mau uso de ponteiros é uma importante fonte de bugs: a alocação constante, deallocation e referenciando que devem ser executada por um programa escrito usando ponteiros torna muito provável que alguns vazamentos de memória irá ocorrer. ponteiros inteligentes tentar evitar que a memória vazamentos, fazendo o recurso desalocação automática: quando o ponteiro para um objeto (ou o último de uma série de ponteiros) é destruído, pois exemplo, porque sai do escopo, o objeto pontiagudo é destruído também.

Seja T uma classe neste tutorial Ponteiros em C ++ pode ser dividido em 3 tipos:

1) ponteiros-primas :

T a;  
T * _ptr = &a; 

Eles mantêm um endereço de memória para um local na memória. Use com cuidado, como programas tornar-se complexa difícil manter o controle.

Ponteiros com dados ou endereço de const {Leia trás}

T a ; 
const T * ptr1 = &a ; 
T const * ptr1 = &a ;

Ponteiro para um tipo de dados T que é uma const. Ou seja, você não pode mudar o tipo de dados usando o ponteiro. ou seja *ptr1 = 19; não funciona. Mas você pode mover o ponteiro. ou seja ptr1++ , ptr1--; etc vai funcionar. Leia trás: ponteiro para tipo T que é const

  T * const ptr2 ;

Um ponteiro const para um tipo de dados T. Ou seja, você não pode mover o ponteiro, mas você pode alterar o valor apontado pelo ponteiro. ie *ptr2 = 19 vai funcionar, mas ptr2++ ; ptr2-- etc não vai funcionar. Leia trás: ponteiro const para um tipo T

const T * const ptr3 ; 

Um ponteiro const para um const tipo de dados T. Ou seja, você não pode mover o ponteiro nem poderá alterar o ponteiro tipo de dados a ser o ponteiro. ie. ptr3-- ; ptr3++ ; *ptr3 = 19; não funcionará

3) Smart ponteiros : {#include <memory>}

Pointer Shared :

  T a ; 
     //shared_ptr<T> shptr(new T) ; not recommended but works 
     shared_ptr<T> shptr = make_shared<T>(); // faster + exception safe

     std::cout << shptr.use_count() ; // 1 //  gives the number of " 
things " pointing to it. 
     T * temp = shptr.get(); // gives a pointer to object

     // shared_pointer used like a regular pointer to call member functions
      shptr->memFn();
     (*shptr).memFn(); 

    //
     shptr.reset() ; // frees the object pointed to be the ptr 
     shptr = nullptr ; // frees the object 
     shptr = make_shared<T>() ; // frees the original object and points to new object

implementada utilizando contagem de referência para manter o controle de quantas "coisas" apontam para o objeto apontado pelo ponteiro. Quando esta contagem vai para 0, o objeto é excluído automaticamente, ou seja, objetou é eliminado quando todo o share_ptr apontando para o objeto sai do escopo. Isso se livrar da dor de cabeça de ter que excluir objetos que você alocou usando nova.

Pointer ruim: Ajuda a lidar com referência cíclico que surge quando usando Pointer Shared Se você tem dois objetos apontado por dois ponteiros compartilhados e há um ponteiro que aponta compartilhada interna a cada outro ponteiro compartilhados em seguida, haverá uma referência cíclica eo objeto não será excluído quando ponteiros compartilhados sair do escopo. Para resolver isso, alterar o membro interno de um shared_ptr para weak_ptr. Nota: Para acessar o elemento apontado por um bloqueio uso ponteiro fraco (), isso retorna um weak_ptr.

T a ; 
shared_ptr<T> shr = make_shared<T>() ; 
weak_ptr<T> wk = shr ; // initialize a weak_ptr from a shared_ptr 
wk.lock()->memFn() ; // use lock to get a shared_ptr 
//   ^^^ Can lead to exception if the shared ptr has gone out of scope
if(!wk.expired()) wk.lock()->memFn() ;
// Check if shared ptr has gone out of scope before access

Veja: Quando é std :: weak_ptr útil

Original Pointer: ponteiro inteligente de peso leve com a propriedade exclusiva. Use quando ponteiro aponta para objetos únicos sem compartilhar os objetos entre os ponteiros.

unique_ptr<T> uptr(new T);
uptr->memFn(); 

//T * ptr = uptr.release(); // uptr becomes null and object is pointed to by ptr
uptr.reset() ; // deletes the object pointed to by uptr 

Para alterar o objeto apontado pelo ptr único, usar o movimento semântica

unique_ptr<T> uptr1(new T);
unique_ptr<T> uptr2(new T);
uptr2 = std::move(uptr1); 
// object pointed by uptr2 is deleted and 
// object pointed by uptr1 is pointed to by uptr2
// uptr1 becomes null 

Referências: Eles podem ser essencialmente embora, como ponteiros const, ou seja, um ponteiro que é const e não pode ser movido com melhor sintaxe.

Veja: que são as diferenças entre uma variável ponteiro e uma variável de referência em C ++?

r-value reference : reference to a temporary object   
l-value reference : reference to an object whose address can be obtained
const reference : reference to a data type which is const and cannot be modified 

Referência: https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ Graças ao Andre por apontar essa questão.

Um ponteiro inteligente é uma classe, um invólucro de um ponteiro normal. Ao contrário ponteiros normais, círculo vida de ponto inteligente é baseado em uma contagem de referência (quanto tempo o objeto ponteiro inteligente é atribuído). Assim, sempre que um ponteiro inteligente é atribuído a um outro, a contagem de referência interna mais além. E sempre que o objeto sai do escopo, a menos de referência contagem de menos.

ponteiro automática, embora aparência semelhante, é totalmente diferente do ponteiro inteligente. É uma classe conveniente que desaloca o recurso sempre que um objeto ponteiro automática sai do escopo variável. Até certo ponto, ele faz um ponteiro (para a memória alocada dinamicamente) funciona de forma semelhante a uma variável de pilha (estaticamente alocado na compilação tempo).

ponteiros inteligentes são aquelas em que você não precisa se preocupar com Memória De-Allocation, compartilhamento de recursos e Transferência.

Você pode muito bem usar esses ponteiro na maneira semelhante como qualquer atribuição funciona em Java. Em Garbage Collector java faz o truque, enquanto em ponteiros inteligentes, o truque é feito por Destructors.

As respostas existentes são bons, mas não cobrem o que fazer quando um ponteiro inteligente não é o (completo) resposta para o problema que você está tentando resolver.

Entre outras coisas (bem explicadas em outras respostas), utilizando um ponteiro inteligente é uma solução possível para como podemos usar uma classe abstrata como um tipo de retorno de função? que foi marcada como uma duplicata desta questão. No entanto, a primeira pergunta a perguntar se tentado a especificar um resumo (ou de facto, qualquer) classe base como um tipo de retorno em C ++ é "o que você realmente quer dizer?". Há uma boa discussão (com outras referências) de programação orientada a objeto idiomática em C ++ (e como isso é diferente de outros idiomas) na documentação do boost recipiente ponteiro biblioteca . Em resumo, em C ++ você tem que pensar sobre a posse. Qual ponteiros inteligentes ajudá-lo, mas não são a única solução, ou sempre uma solução completa (eles não dar-lhe cópia polimórfico) e nem sempre são uma solução que você deseja expor em sua interface (e um retorno de função emite um terrível muito parecido com uma interface). Pode ser suficiente para retornar uma referência, por exemplo. Mas, em todos esses casos (ponteiro inteligente, recipiente ponteiro ou simplesmente retornar uma referência) de ter alterado o retorno de um valor para alguma forma de referência . Se você realmente necessário copiar pode ser necessário adicionar mais clichê "idioma" ou movimento para além OOP idiomática (ou não) em C ++ para o polimorfismo mais genérico usando bibliotecas como Adobe Poly ou Boost.TypeErasure .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top