Ouvi dizer que auto_ptr
está sendo descontinuado no C ++ 11. Qual é a razão para isto?
Também gostaria de saber a diferença entre auto_ptr
e shared_ptr
.
Respostas:
A substituição direta auto_ptr
(ou a coisa mais próxima de uma) é unique_ptr
. No que diz respeito ao "problema", é muito simples: auto_ptr
transfere a propriedade quando é atribuído. unique_ptr
também transfere propriedade, mas graças à codificação da semântica de movimento e à magia das referências rvalue, pode fazê-lo de maneira consideravelmente mais natural. Ele também "se ajusta" ao resto da biblioteca padrão consideravelmente melhor (embora, para ser justo, parte disso seja graças ao resto da biblioteca que muda para acomodar a semântica de movimentação em vez de sempre exigir a cópia).
A mudança no nome também é (IMO) bem-vinda - auto_ptr
não diz muito sobre o que ele tenta automatizar, ao passo que unique_ptr
é uma descrição bastante razoável (embora concisa) do que é fornecido.
auto_ptr
nome: auto sugere automatic como em automatic variable, e se refere a uma coisa que auto_ptr
faz: destruir o recurso gerenciado em seu destruidor (quando ele sai do escopo).
auto_ptr
: open-std.org/jtc1/sc22/wg21/docs/papers/2005/…
std::sort
não tem especialização para unique_ptr
. Em vez disso, foi especificado novamente para nunca mais ser copiado. Então, auto_ptr
realmente faz o trabalho com o moderno sort
. Mas o C ++ 98/03 sort
é apenas um exemplo de algoritmo aqui: qualquer algoritmo genérico (fornecido por std ou escrito pelo usuário) que assume que a sintaxe de cópia tem semântica de cópia provavelmente terá um erro de tempo de execução se usado com auto_ptr
, porque se moveauto_ptr
silenciosamente com sintaxe de cópia . A questão é muito maior do que apenas . sort
Achei as respostas existentes ótimas, mas pelo ponto de vista dos ponteiros. IMO, uma resposta ideal deve ter a resposta da perspectiva do usuário / programador.
Primeira coisa (conforme apontado por Jerry Coffin em sua resposta)
shared_ptr: Se você está preocupado com a liberação de recurso / memória E se você tem mais de uma função que pode estar usando o objeto AT-DIFFERENT vezes, então vá com shared_ptr.
Por DIFFERENT-Times, pense em uma situação onde o objeto-ptr é armazenado em múltiplas estruturas de dados e posteriormente acessado. Vários threads, é claro, é outro exemplo.
unique_ptr: Se tudo que você está preocupado é liberar memória, e o acesso ao objeto é SEQUENCIAL, então vá para unique_ptr.
Por SEQUENTIAL, quero dizer, em qualquer ponto o objeto será acessado a partir de um contexto. Por exemplo, um objeto que foi criado e usado imediatamente após a criação pelo criador. Após a criação, o objeto é armazenado na estrutura de dados FIRST . Então, o objeto é destruído após UMA estrutura de dados ou é movido para a SEGUNDA estrutura de dados.
A partir desta linha, irei me referir a _ptr compartilhado / exclusivo como ponteiros inteligentes. (auto_ptr também é um ponteiro inteligente, MAS por causa de falhas em seu design, para o qual eles estão sendo descontinuados, e que acho que irei apontar nas próximas linhas, eles não devem ser agrupados com ponteiro inteligente.)
O motivo mais importante para o uso de auto_ptr em favor do smart-pointer é a atribuição de semântica. Se não fosse por esse motivo, eles teriam adicionado todas as novidades da semântica de movimentação ao auto_ptr em vez de descontinuá-lo. Uma vez que a semântica de atribuição era o recurso mais rejeitado, eles queriam que esse recurso fosse embora, mas como há um código escrito que usa essa semântica (que o comitê de padrões não pode mudar), eles tiveram que deixar de lado auto_ptr, em vez de modificando-o.
No link: http://www.cplusplus.com/reference/memory/unique_ptr/operator=/
Tipo de atribuições suportadas por unqiue_ptr
De: http://www.cplusplus.com/reference/memory/auto_ptr/operator=/
Tipo de atribuições suportadas por auto_ptr
Agora chegando ao motivo pelo qual a atribuição de cópia em si era tão desagradável, eu tenho esta teoria:
O comportamento não intencional é realmente desagradável e, portanto, não gosto do auto_ptr.
(Para 3,1415926536% dos programadores que intencionalmente desejam transferir a propriedade, o C ++ 11 deu a eles std :: move (), o que deixou sua intenção muito clara para todos os estagiários que irão ler e manter o código.)
auto_ptr
valores apontando para o mesmo objeto (já que eles não dão propriedade compartilhada, o primeiro a morrer deixará o outro com uma herança letal; isso também é válido para o unique_ptr
uso), você pode sugerir o que se pretendia em os restantes 96,8584073465% de todo o uso?
*a=*b;
Aqui, apenas o valor de b é copiado para a. Espero que a propriedade de aeb ainda seja das mesmas pessoas. Você mencionou como a propriedade será transferida. Como será?
auto_ptr
objeto a si mesmo. Atribuir para / de seu valor apontado não tem efeito sobre, nem relevância para, propriedade. Espero que ainda não esteja usando auto_ptr
?
Mais uma tentativa de explicar a diferença ....
Funcionalmente, o C ++ 11's std::unique_ptr
é o "fixo"std::auto_ptr
: ambos são adequados quando - em qualquer momento durante a execução - deve haver um único proprietário de ponteiro inteligente para um objeto apontado.
A diferença crucial está na construção da cópia ou atribuição de outro ponteiro inteligente que não expira, mostrado nas =>
linhas abaixo:
std::auto_ptr<T> ap(...);
std::auto_ptr<T> ap2(get_ap_to_T()); // take expiring ownership
=> std::auto_ptr<T> ap3(ap); // take un-expiring ownership ala ap3(ap.release());
ap->xyz; // oops... can still try to use ap, expecting it to be non-NULL
std::unique_ptr<T> up(...);
std::unique_ptr<T> up2(get_up_to_T()); // take expiring ownership
=> std::unique_ptr<T> up3(up); // COMPILE ERROR: can't take un-expiring ownership
=> std::unique_ptr<T> up4(std::move(up)); // EXPLICIT code allowed
=> std::unique_ptr<T> up4(up.release()); // EXPLICIT code allowed
Acima, ap3
silenciosamente "rouba" a propriedade de *ap
, deixando ap
definido como a nullptr
, e o problema é que isso pode acontecer facilmente, sem que o programador tenha pensado em sua segurança.
Por exemplo, se um class
/ struct
tem um std::auto_ptr
membro, então fazer uma cópia de uma instância irá release
o ponteiro da instância que está sendo copiada: isso é semântica estranha e perigosamente confusa, já que normalmente copiar algo não o modifica. É fácil para o autor da classe / estrutura ignorar a liberação do ponteiro ao raciocinar sobre invariantes e estado e, conseqüentemente, tentar cancelar a referência do ponteiro inteligente enquanto nulo, ou simplesmente não ter ainda o acesso / propriedade esperados dos dados apontados.
auto_ptr não pode ser usado em contêineres STL porque tem um construtor de cópia que não atende aos requisitos do contêiner CopyConstructible . unique_ptr não implementa um construtor de cópia, portanto, os contêineres usam métodos alternativos. unique_ptr pode ser usado em contêineres e é mais rápido para algoritmos std do que shared_ptr.
#include <iostream>
#include <type_traits>
#include <vector>
#include <memory>
using namespace std;
int main() {
cout << boolalpha;
cout << "is_copy_constructible:" << endl;
cout << "auto_ptr: " << is_copy_constructible< auto_ptr<int> >::value << endl;
cout << "unique_ptr: " << is_copy_constructible< unique_ptr<int> >::value << endl;
cout << "shared_ptr: " << is_copy_constructible< shared_ptr<int> >::value << endl;
vector<int> i_v;
i_v.push_back(1);
cout << "i_v=" << i_v[0] << endl;
vector<int> i_v2=i_v;
cout << "i_v2=" << i_v2[0] << endl;
vector< unique_ptr<int> > u_v;
u_v.push_back(unique_ptr<int>(new int(2)));
cout << "u_v=" << *u_v[0] << endl;
//vector< unique_ptr<int> > u_v2=u_v; //will not compile, need is_copy_constructible == true
vector< unique_ptr<int> > u_v2 =std::move(u_v); // but can be moved
cout << "u_v2=" << *u_v2[0] << " length u_v: " <<u_v.size() << endl;
vector< shared_ptr<int> > s_v;
shared_ptr<int> s(new int(3));
s_v.push_back(s);
cout << "s_v=" << *s_v[0] << endl;
vector< shared_ptr<int> > s_v2=s_v;
cout << "s_v2=" << *s_v2[0] << endl;
vector< auto_ptr<int> > a_v; //USAGE ERROR
return 0;
}
>cxx test1.cpp -o test1
test1.cpp: In function âint main()â:
test1.cpp:33:11: warning: âauto_ptrâ is deprecated (declared at /apps/hermes/sw/gcc/gcc-4.8.5/include/c++/4.8.5/backward/auto_ptr.h:87) [-Wdeprecated-declarations]
vector< auto_ptr<int> > a_v; //USAGE ERROR
^
>./test1
is_copy_constructible:
auto_ptr: false
unique_ptr: false
shared_ptr: true
i_v=1
i_v2=1
u_v=2
s_v=3
s_v2=3