Respostas:
É fácil quando você tem propriedades que podem ser atribuídas a cada ponteiro inteligente. Existem três propriedades importantes.
O primeiro significa que um ponteiro inteligente não pode excluir o objeto, porque não o possui. O segundo significa que apenas um ponteiro inteligente pode apontar para o mesmo objeto ao mesmo tempo. Se o ponteiro inteligente deve ser retornado das funções, a propriedade é transferida para o ponteiro inteligente retornado, por exemplo.
O terceiro significa que vários ponteiros inteligentes podem apontar para o mesmo objeto ao mesmo tempo. Isso também se aplica a um ponteiro bruto , no entanto, os ponteiros brutos não possuem um recurso importante: eles não definem se são proprietários ou não. Um compartilhamento de ponteiro inteligente de propriedade excluirá o objeto se todos os proprietários desistirem do objeto. Esse comportamento é necessário com frequência, portanto, os ponteiros inteligentes proprietários compartilhados são amplamente difundidos.
Alguns proprietários de ponteiros inteligentes não suportam nem o segundo nem o terceiro. Portanto, eles não podem ser retornados de funções ou transmitidos para outro lugar. Qual é o mais adequado para os RAII
propósitos em que o ponteiro inteligente é mantido local e é apenas criado para liberar um objeto depois que ele sai do escopo.
A participação da propriedade pode ser implementada com um construtor de cópias. Isso naturalmente copia um ponteiro inteligente e a cópia e o original fazem referência ao mesmo objeto. Atualmente, a transferência de propriedade não pode ser implementada no C ++, porque não há como transferir algo de um objeto para outro suportado pela linguagem: Se você tentar retornar um objeto de uma função, o que está acontecendo é que o objeto é copiado. Portanto, um ponteiro inteligente que implemente a transferência de propriedade deve usar o construtor de cópias para implementar essa transferência de propriedade. No entanto, isso, por sua vez, interrompe seu uso em contêineres, porque os requisitos indicam um certo comportamento do construtor de cópia dos elementos dos contêineres que é incompatível com o chamado comportamento de "construtor móvel" desses ponteiros inteligentes.
O C ++ 1x fornece suporte nativo para transferência de propriedade, introduzindo os chamados "mover construtores" e "mover operadores de atribuição". Ele também vem com um ponteiro inteligente de transferência de propriedade chamado unique_ptr
.
scoped_ptr
é um ponteiro inteligente que não é transferível nem compartilhável. É apenas utilizável se você precisar alocar memória localmente, mas certifique-se de que ela será liberada novamente quando ficar fora do escopo. Mas ainda pode ser trocado por outro scoped_ptr, se você desejar fazer isso.
shared_ptr
é um ponteiro inteligente que compartilha a propriedade (terceiro tipo acima). Ele é contado como referência para ver quando a última cópia sai do escopo e, em seguida, libera o objeto gerenciado.
weak_ptr
é um ponteiro inteligente não proprietário. É usado para referenciar um objeto gerenciado (gerenciado por um shared_ptr) sem adicionar uma contagem de referência. Normalmente, você precisaria obter o ponteiro bruto do shared_ptr e copiá-lo. Mas isso não seria seguro, pois você não teria como verificar quando o objeto foi realmente excluído. Portanto, weak_ptr fornece meios referenciando um objeto gerenciado por shared_ptr. Se você precisar acessar o objeto, poderá bloquear o gerenciamento (para evitar que, em outro thread, um shared_ptr o libere enquanto você usa o objeto) e, em seguida, use-o. Se o fraca_ptr apontar para um objeto já excluído, ele notará você lançando uma exceção. Usar o fraca_ptr é mais benéfico quando você tem uma referência cíclica: A contagem de referência não pode lidar facilmente com essa situação.
intrusive_ptr
é como um shared_ptr, mas não mantém a contagem de referência em um shared_ptr, mas deixa de aumentar / diminuir a contagem para algumas funções auxiliares que precisam ser definidas pelo objeto gerenciado. Isso tem a vantagem de que um objeto já referenciado (que possui uma contagem de referência incrementada por um mecanismo externo de contagem de referência) pode ser inserido em um intrusive_ptr - porque a contagem de referência não é mais interna ao ponteiro inteligente, mas o ponteiro inteligente usa um existente mecanismo de contagem de referência.
unique_ptr
é um ponteiro de transferência de propriedade. Você não pode copiá-lo, mas pode movê-lo usando os construtores de movimento do C ++ 1x:
unique_ptr<type> p(new type);
unique_ptr<type> q(p); // not legal!
unique_ptr<type> r(move(p)); // legal. p is now empty, but r owns the object
unique_ptr<type> s(function_returning_a_unique_ptr()); // legal!
Essa é a semântica que o std :: auto_ptr obedece, mas, devido à falta de suporte nativo para movimentação, ele falha em fornecê-los sem armadilhas. unique_ptr roubará automaticamente recursos de um outro unique_ptr temporário, que é um dos principais recursos da semântica de movimentação. auto_ptr será descontinuado na próxima versão do C ++ Standard em favor de unique_ptr. O C ++ 1x também permitirá empacotar objetos que são apenas móveis, mas não podem ser copiados em contêineres. Assim, você pode inserir unique_ptr's em um vetor, por exemplo. Vou parar por aqui e fazer referência a um bom artigo sobre isso, se você quiser ler mais sobre isso.
auto_ptr
já está obsoleto (C ++ 11).
intrusive_ptr
pode ser preferível a shared_ptr
uma melhor coerência do cache. Aparentemente, o cache tem melhor desempenho se você armazenar a contagem de referência como parte da memória do próprio objeto gerenciado, em vez de um objeto separado. Isso pode ser implementado em um modelo ou superclasse do objeto gerenciado.
scoped_ptr é o mais simples. Quando sai do escopo, é destruído. O código a seguir é ilegal (scoped_ptrs não é copiável), mas ilustra um ponto:
std::vector< scoped_ptr<T> > tPtrVec;
{
scoped_ptr<T> tPtr(new T());
tPtrVec.push_back(tPtr);
// raw T* is freed
}
tPtrVec[0]->DoSomething(); // accessing freed memory
shared_ptr é referência contada. Sempre que ocorre uma cópia ou atribuição, a contagem de referência é incrementada. Sempre que o destruidor de uma instância é acionado, a contagem de referência para o T * bruto é diminuída. Quando é 0, o ponteiro é liberado.
std::vector< shared_ptr<T> > tPtrVec;
{
shared_ptr<T> tPtr(new T());
// This copy to tPtrVec.push_back and ultimately to the vector storage
// causes the reference count to go from 1->2
tPtrVec.push_back(tPtr);
// num references to T goes from 2->1 on the destruction of tPtr
}
tPtrVec[0]->DoSomething(); // raw T* still exists, so this is safe
weak_ptr é uma referência fraca a um ponteiro compartilhado que exige que você verifique se o shared_ptr apontado ainda está por perto
std::vector< weak_ptr<T> > tPtrVec;
{
shared_ptr<T> tPtr(new T());
tPtrVec.push_back(tPtr);
// num references to T goes from 1->0
}
shared_ptr<T> tPtrAccessed = tPtrVec[0].lock();
if (tPtrAccessed[0].get() == 0)
{
cout << "Raw T* was freed, can't access it"
}
else
{
tPtrVec[0]->DoSomething(); // raw
}
intrusive_ptr geralmente é usado quando há um smart ptr de terceiros que você deve usar. Ele chamará uma função livre para adicionar e diminuir a contagem de referência. Consulte o link para aumentar a documentação para obter mais informações.
if (tPtrAccessed[0].get() == 0)
suposto ser if (tPtrAccessed.get() == 0)
?
Não negligencie boost::ptr_container
em nenhuma pesquisa sobre indicadores inteligentes de impulso. Eles podem ser inestimáveis em situações em que um exemplo std::vector<boost::shared_ptr<T> >
seria muito lento.
Eu segundo o conselho sobre como olhar para a documentação. Não é tão assustador quanto parece. E algumas dicas curtas:
scoped_ptr
- um ponteiro excluído automaticamente quando sai do escopo. Nota - nenhuma atribuição é possível, mas não apresenta custos indiretosintrusive_ptr
- ponteiro de contagem de referência sem sobrecarga de smart_ptr
. No entanto, o próprio objeto armazena a contagem de referênciaweak_ptr
- trabalha em conjunto shared_ptr
para lidar com as situações que resultam em dependências circulares (leia a documentação e pesquise no google uma bela imagem;)shared_ptr
- o genérico, mais poderoso (e pesado) dos indicadores inteligentes (daqueles oferecidos pelo impulso)auto_ptr
, que garante que o objeto para o qual ele aponta seja destruído automaticamente quando o controle sair de um escopo. No entanto, possui semântica de cópia diferente da dos demais.unique_ptr
- virá com C ++ 0xResposta à edição: Sim