c++ - titulo - title tag e title heading




O que é um ponteiro inteligente e quando devo usar um? (10)

A maioria dos tipos de ponteiros inteligentes manipula a disposição do ponteiro para o objeto para você. É muito útil porque você não precisa mais pensar em descartar objetos manualmente.

Os ponteiros inteligentes mais comumente usados ​​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 descarte, incluindo casos em que os objetos precisam ser "passados ​​através de limites de DLL" (o caso de pesadelo comum se diferentes libc s forem usadas entre seu código e as DLLs).

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


Aqui está o link para respostas semelhantes: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

Um ponteiro inteligente é um objeto que age, parece e se parece com um ponteiro normal, mas oferece mais funcionalidade. Em C ++, os ponteiros inteligentes são implementados como classes de modelo que encapsulam um ponteiro e substituem os operadores de ponteiro padrão. Eles têm várias vantagens sobre os ponteiros regulares. Eles são garantidos para ser inicializados como ponteiros nulos ou ponteiros para um objeto de heap. Indirection através de um ponteiro nulo é verificado. Nenhuma exclusão é necessária. Objetos são automaticamente liberados quando o último ponteiro para eles desaparece. Um problema significativo com esses ponteiros inteligentes é que, ao contrário dos ponteiros regulares, eles não respeitam a herança. Os ponteiros inteligentes não são 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:
               //...
};

Essa classe implementa um ponteiro inteligente para um objeto do tipo X. O objeto em si está localizado no heap. Aqui está como usá-lo:

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

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

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

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

Entre outras coisas (bem explicadas em outras respostas), usar um ponteiro inteligente é uma solução possível para Como usamos uma classe abstrata como um tipo de retorno de função? que foi marcado como uma duplicata desta questão. No entanto, a primeira pergunta a ser feita, se tentado a especificar uma classe base abstrata (ou, na verdade, qualquer) 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 objetos idiomática em C ++ (e como isso é diferente de outras linguagens) na documentação da biblioteca de contêiner de ponteiro de impulso . Em resumo, em C ++ você precisa pensar em propriedade. Quais indicadores inteligentes ajudam você, mas não são a única solução, ou sempre uma solução completa (eles não fornecem cópia polimórfica) e nem sempre são uma solução que você deseja expor em sua interface (e um retorno de função soa horrível) muito parecido com uma interface). Pode ser suficiente retornar uma referência, por exemplo. Mas em todos esses casos (ponteiro inteligente, contêiner de ponteiro ou simplesmente retornar uma referência), você alterou o retorno de um valor para alguma forma de referência . Se você realmente precisava de uma cópia, talvez seja necessário adicionar mais clichê "idiom" ou ir além do idiomático (ou outro) OOP em C ++ para um polimorfismo mais genérico usando bibliotecas como o Adobe Poly ou Boost.TypeErasure .


Definições fornecidas por Chris, Sergdev e Llyod estão corretas. Eu prefiro uma definição mais simples, apenas para manter minha vida simples: Um ponteiro inteligente é simplesmente uma classe que sobrecarrega os operadores -> e * . O que significa que seu objeto se parece semanticamente com um ponteiro, mas você pode fazer coisas mais auto_ptr , incluindo contagem de referências, 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.


Os indicadores inteligentes são aqueles em que você não precisa se preocupar com a alocação de memória, o compartilhamento de recursos e a transferência.

Você pode muito bem usar esses ponteiros da mesma maneira que qualquer alocação funciona em Java. Em java Garbage Collector faz o truque, enquanto em Smart Pointers, o truque é feito por Destrutores.


Seja T uma classe neste tutorial Ponteiros em C ++ podem ser divididos em 3 tipos:

1) ponteiros Raw :

T a;  
T * _ptr = &a; 

Eles mantêm um endereço de memória para um local na memória. Use com cuidado, pois os programas se tornam difíceis de acompanhar.

Ponteiros com dados const ou endereço {Read backwards}

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

Ponteiro para um tipo de dados T que é um const. Isso significa que você não pode alterar o tipo de dados usando o ponteiro. ie *ptr1 = 19 ; não funciona. Mas você pode mover o ponteiro. isto é, ptr1++ , ptr1-- ; etc vai funcionar. Leia para trás: ponteiro para o tipo T, que é const

  T * const ptr2 ;

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

const T * const ptr3 ; 

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

3) Ponteiros Inteligentes : { #include <memory> }

Ponteiro Compartilhado :

  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

Implementado usando contagem de referência para acompanhar quantas "coisas" apontam para o objeto apontado pelo ponteiro. Quando essa contagem vai para 0, o objeto é automaticamente excluído, ou seja, objeto é excluído quando todo o share_ptr apontando para o objeto sai do escopo. Isso elimina a dor de cabeça de ter que excluir objetos que você alocou usando o novo.

Ponteiro fraco: Ajuda a lidar com referência cíclica que surge ao usar Ponteiro compartilhado Se você tiver dois objetos apontados por dois ponteiros compartilhados e houver um ponteiro interno apontando para o ponteiro compartilhado, haverá uma referência cíclica e o objeto não será ser excluído quando os ponteiros compartilhados ficarem fora do escopo. Para resolver isso, altere o membro interno de um shared_ptr para weak_ptr. Nota: Para acessar o elemento apontado por um ponteiro fraco use lock (), 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 o std :: weak_ptr é útil?

Ponteiro exclusivo: ponteiro inteligente leve com propriedade exclusiva. Use quando o ponteiro apontar 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 mudar o objeto apontado pelo ptr único, use a semântica de movimento

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: Elas podem ser essencialmente como ponteiros, isto é, um ponteiro que é const e não pode ser movido com uma sintaxe melhor.

Veja: Quais são as diferenças entre uma variável de 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 Agradecemos a Andre por apontar esta pergunta.


Um ponteiro inteligente é um objeto que age como um ponteiro, mas também fornece controle sobre a construção, destruição, cópia, movimentação e desreferência.

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

Por exemplo, o Boost fornece as seguintes implementações de ponteiros inteligentes:

  • 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 apontador automaticamente excluído quando sai do escopo. Nenhuma atribuição é possível.
  • intrusive_ptr<T> é outro ponteiro de contagem de referência. Ele fornece melhor desempenho que shared_ptr , mas requer que o tipo T forneça 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 uma descrição linear de cada uma e podem ser usadas conforme a necessidade. Para mais detalhes e exemplos, é possível consultar a documentação do Boost.

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


Um ponteiro inteligente é uma classe que envolve um ponteiro C ++ "bruto" (ou "simples"), para gerenciar a vida útil do objeto que está sendo apontado. Não existe um único tipo de ponteiro inteligente, mas todos eles tentam abstrair um ponteiro bruto de uma maneira prática.

Os ponteiros inteligentes devem ser preferidos aos ponteiros brutos. Se você acha que precisa usar ponteiros (primeiro considere se você realmente usa), você normalmente desejaria usar um ponteiro inteligente, pois isso pode aliviar muitos dos problemas com ponteiros brutos, esquecendo principalmente de excluir o objeto e vazando memória.

Com ponteiros brutos, o programador deve destruir explicitamente o objeto quando não for 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 por comparação define uma política para quando o objeto é destruído. Você ainda precisa criar o objeto, mas não precisa mais se preocupar em 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 wrapper de ponteiro inteligente, como implementado por boost::scoped_ptr ou std::unique_ptr .

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

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

Observe que instâncias scoped_ptr não podem ser copiadas. Isso impede que o ponteiro seja excluído várias vezes (incorretamente). Você pode, no entanto, passar referências a ele para outras funções que você chama.

Os ponteiros com escopo são úteis quando você deseja vincular a vida útil do objeto a um determinado bloco de código ou, se incorporado como dados de membro dentro de outro objeto, o tempo de vida desse outro objeto. O objeto existe até que o bloco de código contendo seja encerrado, ou até que o objeto contido seja destruído.

Uma política de apontador inteligente mais complexa envolve a referência contando o ponteiro. Isso permite que o ponteiro seja copiado. Quando a última "referência" ao objeto é destruída, 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.

Ponteiros de referência contados são muito úteis quando o tempo de vida do seu objeto é muito mais complicado e não está vinculado diretamente a uma seção particular de código ou a outro objeto.

Há uma desvantagem de referenciar ponteiros contados - a possibilidade de criar uma referência pendente:

// 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 é criar referências circulares:

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

boost::shared_ptr<Owner> p1 (new Owner());
boost::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 contornar esse problema, tanto o Boost quanto o C ++ 11 definiram um weak_ptr para definir uma referência fraca (não contada) a um shared_ptr .

ATUALIZAR

Essa resposta é bastante antiga e, portanto, descreve o que era "bom" na época, que eram os indicadores inteligentes fornecidos pela biblioteca Boost. Desde C ++ 11, a biblioteca padrão forneceu tipos de ponteiros inteligentes suficientes, e assim 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 com escopo definido, exceto que ele também tem a capacidade perigosa "especial" de ser copiada - o que também transfere inesperadamente a propriedade! Está obsoleto nos padrões mais recentes, então você não deve usá-lo. Use o std::unique_ptr vez disso.

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.

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

A pequena introdução está disponível na página Smart Pointers - What, Why, Which? .

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

Outro tipo conveniente é o boost::shared_ptr que implementa a contagem de referência e desaloca automaticamente a memória quando não há referências ao objeto. Isso ajuda a evitar vazamentos de memória e é fácil de usar para implementar o RAII .

O assunto é coberto em profundidade no livro "Modelos C ++: O Guia Completo" por David Vandevoorde, Nicolai M. Josuttis , capítulo Capítulo 20. Ponteiros Inteligentes. Alguns tópicos abordados:


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

Na ciência da computação, um ponteiro inteligente é um tipo de dados abstrato que simula um ponteiro enquanto fornece recursos adicionais, como coleta automática de lixo ou verificação de limites. Esses recursos adicionais destinam-se a reduzir erros causados ​​pelo uso indevido de ponteiros, mantendo a eficiência. Os indicadores inteligentes geralmente acompanham os objetos que apontam para eles com o objetivo de gerenciar a memória. O uso indevido de ponteiros é uma fonte importante de erros: a alocação, desalocação e referência constantes que devem ser executadas por um programa escrito usando ponteiros torna muito provável que ocorram vazamentos de memória. Os ponteiros inteligentes tentam impedir vazamentos de memória, tornando automática a desalocação de recursos: quando o ponteiro para um objeto (ou o último em uma série de ponteiros) é destruído, por exemplo, porque ele sai do escopo, o objeto apontado também é destruído.





c++-faq