std :: auto_ptr para std :: unique_ptr

185

Com a chegada do novo padrão (e peças já disponíveis em alguns compiladores), o novo tipo std::unique_ptrdeve ser um substituto std::auto_ptr.

O uso deles se sobrepõe exatamente (para que eu possa localizar / substituir globalmente no meu código (não que eu faria isso, mas se o fizesse)) ou devo estar ciente de algumas diferenças que não são aparentes na leitura da documentação?

Além disso, se for um substituto direto, por que dar um novo nome ao invés de apenas melhorar o std::auto_ptr?

Martin York
fonte

Respostas:

219

Você não pode localizar / substituir globalmente porque pode copiar um auto_ptr(com consequências conhecidas), mas um unique_ptrsó pode ser movido. Qualquer coisa que pareça

std::auto_ptr<int> p(new int);
std::auto_ptr<int> p2 = p; 

terá que se tornar pelo menos assim

std::unique_ptr<int> p(new int);
std::unique_ptr<int> p2 = std::move(p);

Quanto a outras diferenças, unique_ptrpode manipular matrizes corretamente (ele chamará delete[], enquanto auto_ptrtentará chamar delete.

Cubbi
fonte
101
por outro lado, fazer essa localização / substituição resultará apenas em erros de compilação, e não quebrará o código silenciosamente até onde eu posso ver. Por isso, é seguro para fazer, se você corrigir manualmente os erros de compilação depois
jalf
7
@ jalf: Na verdade, não consigo pensar em um contra-exemplo que seria bem definido com auto_ptrs e UB com unique_ptrs.
Cubbi
1
então parece que unique_ptr é um aprimoramento do auto_ptr: array apoio & ambigüidade remove
Baiyan Huang
92

std::auto_ptre std::unique_ptrsão incompatíveis em alguns aspectos e uma queda na substituição em outros. Portanto, nenhuma localização / substituição não é boa o suficiente. No entanto, após um trabalho de localização / substituição, os erros de compilação devem corrigir tudo, exceto casos de canto estranhos. A maioria dos erros de compilação exigirá a adição de um std::move.

  • Variável do escopo da função:
    100% compatível, desde que você não o passe por valor para outra função.
  • Tipo de retorno:
    não é 100% compatível, mas 99% compatível não parece errado.
  • Parâmetro de função por valor:
    100% compatível com uma ressalva, unique_ptrs deve ser passado por uma std::movechamada. Este é simples, pois o compilador reclamará se você não acertar.
  • Parâmetro de função por referência:
    100% compatível.
  • Variável de membro da classe:
    Essa é complicada. std::auto_ptrAs cópias semânticas são más. Se a classe não permitir a cópia, haverá std::unique_ptruma queda na substituição. No entanto, se você tentou dar à classe uma semântica de cópia razoável, precisará alterar o std::auto_ptrcódigo de manipulação. Isso é simples, pois o compilador reclamará se você não acertar. Se você permitiu a cópia de uma classe com um std::auto_ptrmembro sem código especial, tenha vergonha e boa sorte.

Em resumo, std::unique_ptré ininterrupto std::auto_ptr. Ele não permite comportamentos em tempo de compilação que geralmente eram erros ao usar a std::auto_ptr. Portanto, se você usou std::auto_ptros cuidados necessários, a mudança para std::unique_ptrdeve ser simples. Se você confiou no std::auto_ptrcomportamento estranho de, precisa refatorar seu código de qualquer maneira.

deft_code
fonte
8
+1 para "você precisa refatorar seu código mesmo assim". auto_ptrs são bons apenas para o que 20.4.5 / 3 diz que são bons.
Cubbi
8
Deixe-me acrescentar a isso que você deve, por todos os meios, substituir auto_ptr por unique_ptr no seu código e corrigir os erros de compilação. Você ficaria surpreso com quantos erros isso descobrirá.
Bartosz Milewski
36

AFAIK, unique_ptrnão é um substituto direto. A principal falha que ele corrige é a transferência implícita de propriedade.

std::auto_ptr<int> a(new int(10)), b;
b = a; //implicitly transfers ownership

std::unique_ptr<int> a(new int(10)), b;
b = std::move(a); //ownership must be transferred explicitly

Por outro lado, unique_ptrterá recursos completamente novos: eles podem ser armazenados em contêineres.

UncleBens
fonte
8
Scott Meyers também mencionou em seu "Effective C ++" (3ª Edição) Item 13 (página 64) que os contêineres STL exigem que seu conteúdo exiba um comportamento de cópia "normal", portanto, contêineres auto_ptrnão são permitidos.
Qiang Xu
31

Herb Sutter tem uma boa explicação sobre GotW # 89 :

Qual é o problema do auto_ptr? O auto_ptr é caracterizado como uma tentativa valiosa de criar um unique_ptr antes que o C ++ tivesse semântica de movimentação. O auto_ptr agora está obsoleto e não deve ser usado no novo código.

Se você possui auto_ptr em uma base de código existente, quando tiver uma chance, tente fazer uma pesquisa e substituição global de auto_ptr para unique_ptr; a grande maioria dos usos funcionará da mesma maneira e poderá expor (como um erro em tempo de compilação) ou corrigir (silenciosamente) um bug ou dois que você não sabia que tinha.

Em outras palavras, enquanto uma pesquisa e substituição global pode "interromper" seu código temporariamente, você deve fazê-lo de qualquer maneira: pode levar algum tempo para corrigir os erros de compilação, mas poupará muito mais problemas a longo prazo.

ValarDohaeris
fonte
Ótimo link. Muito obrigado!
FotNelton