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

1821

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

Alex Reynolds
fonte
7
Confira esta pergunta: <br> ponteiros inteligentes: Ou que possui você, baby
Martin Iorque
2
Observe que a implementação do std :: auto_ptr no Visual Studio 2005 está horrivelmente quebrada. <br> http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98871 <br> <br> http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101842 Use o aumentar os em vez disso.
Richard Richard
25
Dois excelentes artigos sobre o assunto: - Ponteiros inteligentes - O que, por que, qual? - Guru da Semana # 25
Lazer
1
Aqui está o capítulo (gratuito) de Alexandrescu sobre os detalhes básicos da criação de indicadores inteligentes de diferentes sabores: informit.com/articles/article.aspx?p=31529 Em sua implementação, ele usa argumentos de modelo como "políticas" para especificar quais atributos ele deseja ( por exemplo, contagem de referência), enquanto a biblioteca padrão usa classes separadas. Note que ele também estava escrevendo antes que as referências rvalue estivessem disponíveis para tornar possível algo como std :: unique_ptr.
metal
Gostaria de acrescentar mais um ponto à pergunta acima: o ponteiro inteligente std :: shared_ptr não possui um operador subscrito e não suporta aritmética de ponter, podemos usar get () para obter um ponteiro embutido.
m Suresh

Respostas:

1884

ATUALIZAR

Essa resposta é bastante antiga e, portanto, descreve o que era 'bom' na época, que eram indicadores inteligentes fornecidos pela biblioteca Boost. Desde o C ++ 11, a biblioteca padrão fornece tipos suficientes de ponteiros inteligentes e, portanto, você deve favorecer o uso de std::unique_ptr, std::shared_ptre std::weak_ptr.

Havia também std::auto_ptr. Era muito parecido com um ponteiro de escopo, exceto que também tinha a capacidade perigosa "especial" de ser copiada - o que também transfere inesperadamente a propriedade.
Ele foi descontinuado no C ++ 11 e removido no C ++ 17 , portanto, você não deve usá-lo.

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 ANTIGA

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

Ponteiros inteligentes devem ter preferência sobre ponteiros brutos. Se você acha que precisa usar ponteiros (primeiro considere se realmente o faz), normalmente deseja usar um ponteiro inteligente, pois isso pode aliviar muitos dos problemas com ponteiros brutos, principalmente esquecendo de excluir o objeto e vazar memória.

Com ponteiros brutos, o programador precisa destruir explicitamente 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 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 do ponteiro inteligente, como implementado por boost::scoped_ptrou 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.
}

Observe que as std::unique_ptrinstâncias não podem ser copiadas. Isso evita que o ponteiro seja excluído várias vezes (incorretamente). No entanto, você pode passar referências a ele para outras funções chamadas.

std::unique_ptrs são úteis quando você deseja vincular a vida útil do objeto a um bloco de código específico, ou se você o incorporou como dados do membro em outro objeto, a vida útil desse outro objeto. O objeto existe até que o bloco de código contido seja encerrado ou até que o próprio objeto contido seja destruído.

Uma política de ponteiro inteligente mais complexa envolve a contagem de referência do 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_ptre 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.

Os ponteiros contados por referência são muito úteis quando a vida útil do seu objeto é muito mais complicada e não está vinculada diretamente a uma seção específica do código ou a outro objeto.

Há uma desvantagem em 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 {
   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 contornar esse problema, o Boost e o C ++ 11 definiram a weak_ptrpara definir uma referência fraca (não contada) para a shared_ptr.

Lloyd
fonte
7
Você quer dizer em std::auto_ptr<MyObject> p1 (new MyObject());vez de std::auto_ptr<MyObject> p1 (new Owner());?
Mateen Ulhaq
35
Resposta incrível. Seria bom se ele fosse atualizado para o c ++ 11. Encontrei esta resposta procurando informações sobre o novo padrão 11 e seria bom se futuros visitantes pudessem encontrar as informações atualizadas. Eu sei que auto_ptr foi preterido. Acredito que shated_ptr e weak_ptr existem como descrito, e acho que o scoped_ptr agora é unique_ptr no padrão. Se isso for verdade, esta resposta pode ser atualizada, por favor?
SaulBack 11/09/12
16
Dizer que a possibilidade de criar uma referência pendente é uma desvantagem para referenciar ponteiros contados é absolutamente insano. Possíveis referências pendentes são uma desvantagem de qualquer ponteiro C ++ . De fato, é exatamente essa desvantagem que os ponteiros inteligentes devem aliviar .
Michael Dorst
16
Se você declarar um ponteiro para um ponteiro inteligente (como foi feito no exemplo), conscientemente desistirá de todos os benefícios do ponteiro inteligente. Isso não é uma desvantagem ou uma falha de design, é o uso mais idiota que se possa imaginar.
Michael Dorst
3
A const std::auto_ptré seguro de usar, se você estiver preso ao C ++ 03. Usei bastante o padrão pimpl até ter acesso ao C ++ 11.
precisa saber é o seguinte
303

Aqui está uma resposta simples para esses dias do C ++ moderno (C ++ 11 e posterior):

  • O que é um ponteiro inteligente?
    É um tipo cujos valores podem ser usados ​​como ponteiros, mas que fornece o recurso adicional do gerenciamento automático de memória: Quando um ponteiro inteligente não está mais em uso, a memória para a qual ele aponta é desalocada (consulte também a definição mais detalhada na Wikipedia ).
  • Quando devo usar um?
    No código que envolve rastrear a propriedade de um pedaço de memória, alocar ou desalocar; o ponteiro inteligente geralmente evita a necessidade de fazer essas coisas explicitamente.
  • Mas qual ponteiro inteligente devo usar em qual desses casos?
    • Use std::unique_ptrquando não pretender manter várias referências ao mesmo objeto. Por exemplo, use-o como um ponteiro para a memória que é alocado na entrada de algum escopo e desalocado na saída do escopo.
    • Use std::shared_ptrquando quiser se referir ao seu objeto a partir de vários locais - e não deseja que seu objeto seja desalocado até que todas essas referências tenham desaparecido.
    • Use std::weak_ptrquando você quiser se referir ao seu objeto de vários lugares - para aquelas referências para as quais não há problema em ignorar e desalocar (para que elas notem que o objeto desapareceu quando você tenta desreferenciar).
    • Não use os boost::ponteiros inteligentes ou, std::auto_ptrexceto em casos especiais, os quais você pode ler se precisar.
  • Ei, eu não perguntei qual usar!
    Ah, mas você realmente queria admitir.
  • Então, quando devo usar ponteiros regulares?
    Principalmente no código alheio à propriedade da memória. Isso normalmente ocorre em funções que obtêm um ponteiro de outro lugar e não alocam nem desalocam, e não armazenam uma cópia do ponteiro que supera sua execução.
einpoklum
fonte
5
Vale ressaltar que, embora os ponteiros inteligentes (proprietários) ajudem no gerenciamento adequado da memória, os ponteiros brutos (não proprietários) ainda são úteis para outros fins organizacionais nas estruturas de dados. Herb Sutter fez uma ótima apresentação sobre este assunto no CppCon 2016, que você pode ver no YouTube: Leak-Freedom in C ++ ... Por padrão.
Wiktor.wandachowicz
1
@ wiktor.wandachowicz T*é para o std::unique_ptr<T>que std::weak_ptr<T>éstd::shared_ptr<T>
Caleth
@Caleth: Não, eu não diria isso.
einpoklum
1
@TonyTannous: Com respeito - Foi uma grande edição; e não sinto que minha resposta, abstrata, precise dela. Sugiro que você faça do exemplo uma resposta separada, no link para um comentário.
einpoklum 22/01
112

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

Pequena introdução está disponível na página Ponteiros inteligentes - O que, por quê, qual? .

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

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

O assunto é abordado 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:

sergtk
fonte
2
O aviso std::auto_ptrfoi descontinuado e desencorajador, pois você pode transferir a propriedade acidentalmente. - C ++ 11 elimina a necessidade de Boost, use: std::unique_ptr, std::shared_ptrestd::weak_ptr
ninMonkey
42

As definições fornecidas por Chris, Sergdev e Llyod estão corretas. No entanto, 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 fazê-lo de maneira mais interessante, incluindo contagem de referências, destruição automática etc. shared_ptre auto_ptré suficiente na maioria dos casos, mas é fornecido com seu próprio conjunto de pequenas idiossincrasias.

Sridhar Iyer
fonte
30

Um ponteiro inteligente é como um ponteiro normal (digitado), como "char *", exceto quando o ponteiro em si fica fora do escopo, o que ele aponta também é excluído. Você pode usá-lo como faria com um ponteiro comum, usando "->", mas não se precisar de um ponteiro real para os dados. Para isso, você pode usar "& * ptr".

É útil para:

  • Objetos que devem ser alocados com novos, mas que você gostaria de ter o mesmo tempo de vida útil de algo nessa pilha. Se o objeto estiver atribuído a um ponteiro inteligente, eles serão excluídos quando o programa sair dessa função / bloco.

  • Membros de dados de classes, para que, quando o objeto for excluído, todos os dados pertencentes também sejam excluídos, sem nenhum código especial no destruidor (você precisará ter certeza de que o destruidor é virtual, o que é quase sempre uma boa coisa a fazer) .

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

  • ... o ponteiro não deve realmente possuir os dados ... ou seja, quando você está apenas usando os dados, mas deseja que ele sobreviva à função em que os está referenciando.
  • ... o ponteiro inteligente não será destruído em algum momento. Você não deseja que ele fique na memória que nunca é destruída (como em um objeto que é alocado dinamicamente, mas não será excluído explicitamente).
  • ... dois ponteiros inteligentes podem apontar para os mesmos dados. (No entanto, existem indicadores ainda mais inteligentes que lidarão com isso ... isso é chamado de contagem de referência .)

Veja também:

mercados
fonte
18

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

Os ponteiros inteligentes mais 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 ​​pelos limites da DLL" (o caso de pesadelo comum se diferentes libcs forem usados ​​entre o código e as DLLs).

Chris Jester-Young
fonte
18

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

Pode-se implementar o seu próprio ponteiro inteligente, mas muitas bibliotecas também fornecem implementações de ponteiros inteligentes, 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 o Tuso de uma contagem de referência para determinar quando o objeto não é mais necessário.
  • scoped_ptr<T>é um ponteiro excluído automaticamente quando sai do escopo. Nenhuma atribuição é possível.
  • intrusive_ptr<T>é outro ponteiro de contagem de referência. Ele fornece um desempenho melhor que shared_ptr, mas requer que o tipo Tforneça seu próprio mecanismo de contagem de referência.
  • weak_ptr<T>é um ponteiro fraco, trabalhando em conjunto com shared_ptrpara 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.

Essas são apenas uma descrição linear de cada uma e podem ser usadas conforme a necessidade. Para obter mais detalhes e exemplos, consulte a documentação do Boost.

Além disso, a biblioteca padrão C ++ fornece três ponteiros inteligentes; std::unique_ptrpara propriedade exclusiva, std::shared_ptrpropriedade compartilhada e std::weak_ptr. std::auto_ptrexistia em C ++ 03, mas agora está obsoleta.

Saqlain
fonte
Explique por que scoped_ptrnão é como um declarado localmente const unique_ptr- que também é excluído ao sair do escopo.
Einpoklum
11

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

Um ponteiro inteligente é um objeto que age, parece e parece um ponteiro normal, mas oferece mais funcionalidade. No C ++, 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 ponteiros regulares. Eles são garantidos para serem inicializados como ponteiros nulos ou ponteiros para um objeto de heap. A indicação através de um ponteiro nulo é verificada. Nenhuma exclusão é necessária. Os objetos são liberados automaticamente quando o último ponteiro para eles desaparece. Um problema significativo com esses ponteiros inteligentes é que, diferentemente dos ponteiros regulares, eles não respeitam a herança. Ponteiros inteligentes não são atraentes para código polimórfico. Dado 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 próprio objeto está localizado no heap. Aqui está como usá-lo:

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

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

cout<<*p;
p->raise_salary(0.5);
Santosh
fonte
9

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 e fornece recursos adicionais, como coleta automática de lixo ou verificação de limites. Esses recursos adicionais visam reduzir os erros causados ​​pelo uso indevido dos ponteiros, mantendo a eficiência. Os ponteiros inteligentes normalmente acompanham os objetos que apontam para eles para fins de gerenciamento de memória. O uso indevido de ponteiros é uma das principais fontes de erros: a alocação, desalocação e referência constantes que devem ser executadas por um programa escrito usando ponteiros tornam muito provável que ocorram vazamentos de memória. Ponteiros inteligentes tentam impedir vazamentos de memória, tornando a desalocação automática de recursos: quando o ponteiro de um objeto (ou o último de uma série de ponteiros) é destruído,

Jorge Ferreira
fonte
6

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

1) ponteiros brutos :

T a;  
T * _ptr = &a; 

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

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

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 alterar o tipo de dados usando o ponteiro. ie *ptr1 = 19; não funciona. Mas você pode mover o ponteiro. ie 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. ou seja, *ptr2 = 19vai funcionar, mas ptr2++ ; ptr2--etc não vai funcionar. Ler 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 alterar o ponteiro do tipo de dados para ele. 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 a contagem de referência para acompanhar quantas "coisas" apontam para o objeto apontado pelo ponteiro. Quando essa contagem chega a 0, o objeto é excluído automaticamente, ou seja, o objeto é excluído quando todo o share_ptr que aponta para o objeto sai do escopo. Isso elimina a dor de cabeça de ter que excluir objetos que você alocou usando new.

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

Ponteiro exclusivo: ponteiro inteligente leve com propriedade exclusiva. Use quando o ponteiro aponta para objetos exclusivos 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 exclusivo, use mover 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: Elas podem ser essencialmente consideradas ponteiros const, ou seja, um ponteiro que é const e não pode ser movido com melhor sintaxe.

Consulte: 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 Agradecimentos a Andre por apontar esta pergunta.

nnrales
fonte
3

Um ponteiro inteligente é uma classe, um invólucro de um ponteiro normal. Diferentemente dos ponteiros normais, o ciclo de vida do ponto inteligente é baseado em uma contagem de referência (quantas vezes o objeto do ponteiro inteligente é atribuído). Portanto, sempre que um ponteiro inteligente é atribuído a outro, a referência interna conta mais mais. E sempre que o objeto sai do escopo, a contagem de referência menos menos.

O ponteiro automático, embora parecido, é totalmente diferente do ponteiro inteligente. É uma classe conveniente que desaloca o recurso sempre que um objeto de ponteiro automático sai do escopo variável. Até certo ponto, faz um ponteiro (para memória alocada dinamicamente) funcionar de maneira semelhante a uma variável de pilha (alocada estaticamente no tempo de compilação).

Trombe
fonte
2

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

Você pode muito bem usar esse ponteiro da mesma maneira que qualquer alocação funciona em Java. No java, o Garbage Collector faz o truque, enquanto no Smart Pointers, o truque é feito pelos destruidores.

Daksh
fonte
1

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 (explicadas bem em outras respostas), o uso de 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 duplicado desta pergunta. No entanto, a primeira pergunta a perguntar se é tentado especificar uma classe base abstrata (ou de fato qualquer) como um tipo de retorno em C ++ é "o que você realmente quer dizer?". Há uma boa discussão (com referências adicionais) da programação orientada a objetos idiomáticos em C ++ (e como isso é diferente de outras linguagens) na documentação da biblioteca de contêiner de ponteiro de aumento. 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 são uma solução completa (eles não oferecem cópia polimórfica) e nem sempre são uma solução que você deseja expor em sua interface (e o retorno de uma função parece 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 copiar, pode ser necessário adicionar mais "idiomática" padrão ou ir além do OOP idiomático (ou não) no C ++ para um polimorfismo mais genérico usando bibliotecas como Adobe Poly ou Boost.TypeErasure.

da77a
fonte