Definitivamente um +1 nisso, porque eu já vi tantas pessoas entenderem isso errado. É uma ótima pergunta a fazer.
Twokats
Por favor, leia também o item relacionado. Esta questão é considerada aqui do outro lado. Pode ser útil entender mais sobre os contêineres auto_ptr e STL. stackoverflow.com/questions/8630552/…
movesemântica e unique_ptrforam projetados para evitar os problemas relacionados a auto_ptr. No C ++ 03, a linguagem não era poderosa o suficiente para escrever uma classe como auto_ptraquela que se comporta corretamente e com segurança em todos os cenários, pois o compilador e a linguagem não conseguiram distinguir os valores de l e r, de modo que alguns "hacks" foram usados para obter o comportamento desejado a maior parte do tempo.
O padrão C ++ diz que um elemento STL deve ser "cópia construtível" e "atribuível". Em outras palavras, um elemento deve poder ser atribuído ou copiado e os dois elementos são logicamente independentes. std::auto_ptrnão cumpre esse requisito.
Tomemos por exemplo este código:
class X{};
std::vector<std::auto_ptr<X>> vecX;
vecX.push_back(new X);
std::auto_ptr<X> pX = vecX[0];// vecX[0] is assigned NULL.
Você também deve considerar os contêineres do ponteiro de aumento, se não precisar de propriedade compartilhada.
me22 10/10/09
4
unique_ptrtambém não permite copiar, portanto, certas operações STL não funcionarão corretamente, a menos que possam usar sua semântica de movimentação.
9133 Mike Weller
4
"Para superar essa limitação, você deve usar o std::unique_ptr": esse modelo de classe só pode existir por causa da semântica de movimentação (sua especificação requer referências de rvalue), portanto, fundamentalmente, requer C ++ 11. No entanto (e relacionado), o C ++ 11 Standard não diz mais que um tipo de elemento STL deve ser "copiável-construtível" e "atribuível"; ser move-construtível e move-designável é suficiente. De fato, as unique_ptrinstâncias são apenas construtivas e atribuíveis a movimentação. Mas também são auto_ptrexemplos! Como conseqüência, no C ++ 11, você pode fazer auto_ptro que pode fazer unique_ptr.
Marc van Leeuwen
@MarcvanLeeuwen a menos que você resete releasequando necessário
catraca aberração
2
@ratchetfreak: Hmm, eu não entendo. O que? "a menos que você resete release", não vejo como isso se aplica a nada no meu comentário. Observe que ambos auto_ptre unique_ptrpossuem esses dois métodos, e eles fazem a mesma coisa nos dois casos.
Marc van Leeuwen
66
A semântica de cópia de auto_ptrnão é compatível com os contêineres.
Especificamente, copiar um auto_ptrpara o outro não cria dois objetos iguais, pois um deles perdeu a propriedade do ponteiro.
Mais especificamente, copiar um auto_ptrfaz com que uma das cópias solte o ponteiro. Qual desses restos no contêiner não está definido. Portanto, você pode perder aleatoriamente o acesso aos ponteiros se armazenar auto_ptrsnos contêineres.
Porque acho que, nos próximos dois anos, ele provavelmente lidou com o problema em questão.
Filhote de cachorro
27
@DeadMG: sim, você está correto. Mas esse não era meu objetivo. Se alguém chegar a esse tópico em algum momento e quiser aprender sobre auto_ptressas coisas, esses links serão úteis, tenho certeza.
Lazer
Há muitas duplicatas mais recentes.
Filhote
8
@DeadMG: Esta questão não foi encerrada como duplicada e, portanto, está aberta para extensão. Lazer disse o que não foi dito antes aqui. Eu acho que ele veio por acaso.
Sebastian Mach
As explicações no segundo link, que analisam o problema após a chamada sort(), são mais claras do que todas as respostas aqui.
chaosink
17
Os contêineres da STL precisam ser capazes de copiar os itens armazenados neles e foram projetados para esperar que o original e a cópia sejam equivalentes. objetos de ponteiro automático têm um contrato completamente diferente, pelo qual a cópia cria uma transferência de propriedade. Isso significa que os contêineres de auto_ptr exibirão um comportamento estranho, dependendo do uso.
Há uma descrição detalhada do que pode dar errado no item 8 do STL eficaz (Scott Meyers) e também uma descrição não tão detalhada no item 13 do C ++ eficaz (Scott Meyers).
Os contêineres STL armazenam cópias dos itens contidos. Quando um auto_ptr é copiado, ele define o ptr antigo como nulo. Muitos métodos de contêiner são quebrados por esse comportamento.
Mas, ao usar unique_ptr, você obtém praticamente a mesma coisa, pois apenas um unique_ptr pode ter a propriedade do objeto?
Tracer
2
O @Tracer, unique_ptrcomo qualquer objeto C ++ 11 adequado, só pode transferir a propriedade de seu recurso quando construído ou movido, movendo-o, garantindo que o programador passe deliberadamente um std::move(sourceObject)ou um temporário, em vez de passar um lvalue e, de maneira não intuitiva / imprevisível, alterando-o por a tarefa de cópia ... que, como enfatizado aqui, era um problema central auto_ptr.
underscore_d
4
A norma C ++ 03 (ISO-IEC 14882-2003) diz na cláusula 20.4.5, parágrafo 3:
[...] [ Nota: [...] auto_ptr não atende aos requisitos de CopyConstructible e Assignable para elementos de contêiner da Biblioteca Padrão e, assim, instanciar um contêiner da Biblioteca Padrão com um auto_ptr resulta em comportamento indefinido. - nota final ]
A norma C ++ 11 (ISO-IEC 14882-2011) diz no apêndice D.10.1, parágrafo 3:
[...]
Nota: [...] Instâncias de auto_ptr atender os requisitos da MoveConstructible e MoveAssignable, mas não atender aos requisitos de CopyConstructible e CopyAssignable. - nota final]
A norma C ++ 14 (ISO-IEC 14882-2014) diz no apêndice C.4.2 Anexo D: recursos de compatibilidade:
Alteração : Os modelos de classe auto_ptr, unary_function e binary_function, os modelos de função random_shuffle e os modelos de função (e seus tipos de retorno) ptr_fun, mem_fun, mem_fun_ref, bind1st e bind2nd não estão definidos. Justificativa : Substituída por novos recursos. Efeito no recurso original : O código C ++ 2014 válido que usa esses modelos de classe e modelos de função pode falhar na compilação neste Padrão Internacional.
move
semântica eunique_ptr
foram projetados para evitar os problemas relacionados aauto_ptr
. No C ++ 03, a linguagem não era poderosa o suficiente para escrever uma classe comoauto_ptr
aquela que se comporta corretamente e com segurança em todos os cenários, pois o compilador e a linguagem não conseguiram distinguir os valores de l e r, de modo que alguns "hacks" foram usados para obter o comportamento desejado a maior parte do tempo.Respostas:
O padrão C ++ diz que um elemento STL deve ser "cópia construtível" e "atribuível". Em outras palavras, um elemento deve poder ser atribuído ou copiado e os dois elementos são logicamente independentes.
std::auto_ptr
não cumpre esse requisito.Tomemos por exemplo este código:
Para superar essa limitação, você deve usar o
std::unique_ptr
,std::shared_ptr
oustd::weak_ptr
ponteiros inteligentes ou o impulso equivalentes, se você não tem C ++ 11. Aqui está a documentação da biblioteca de impulso para esses ponteiros inteligentes.fonte
unique_ptr
também não permite copiar, portanto, certas operações STL não funcionarão corretamente, a menos que possam usar sua semântica de movimentação.std::unique_ptr
": esse modelo de classe só pode existir por causa da semântica de movimentação (sua especificação requer referências de rvalue), portanto, fundamentalmente, requer C ++ 11. No entanto (e relacionado), o C ++ 11 Standard não diz mais que um tipo de elemento STL deve ser "copiável-construtível" e "atribuível"; ser move-construtível e move-designável é suficiente. De fato, asunique_ptr
instâncias são apenas construtivas e atribuíveis a movimentação. Mas também sãoauto_ptr
exemplos! Como conseqüência, no C ++ 11, você pode fazerauto_ptr
o que pode fazerunique_ptr
.reset
erelease
quando necessárioreset
erelease
", não vejo como isso se aplica a nada no meu comentário. Observe que ambosauto_ptr
eunique_ptr
possuem esses dois métodos, e eles fazem a mesma coisa nos dois casos.A semântica de cópia de
auto_ptr
não é compatível com os contêineres.Especificamente, copiar um
auto_ptr
para o outro não cria dois objetos iguais, pois um deles perdeu a propriedade do ponteiro.Mais especificamente, copiar um
auto_ptr
faz com que uma das cópias solte o ponteiro. Qual desses restos no contêiner não está definido. Portanto, você pode perder aleatoriamente o acesso aos ponteiros se armazenarauto_ptrs
nos contêineres.fonte
Dois artigos super excelentes sobre o assunto:
fonte
auto_ptr
essas coisas, esses links serão úteis, tenho certeza.sort()
, são mais claras do que todas as respostas aqui.Os contêineres da STL precisam ser capazes de copiar os itens armazenados neles e foram projetados para esperar que o original e a cópia sejam equivalentes. objetos de ponteiro automático têm um contrato completamente diferente, pelo qual a cópia cria uma transferência de propriedade. Isso significa que os contêineres de auto_ptr exibirão um comportamento estranho, dependendo do uso.
Há uma descrição detalhada do que pode dar errado no item 8 do STL eficaz (Scott Meyers) e também uma descrição não tão detalhada no item 13 do C ++ eficaz (Scott Meyers).
fonte
Os contêineres STL armazenam cópias dos itens contidos. Quando um auto_ptr é copiado, ele define o ptr antigo como nulo. Muitos métodos de contêiner são quebrados por esse comportamento.
fonte
unique_ptr
como qualquer objeto C ++ 11 adequado, só pode transferir a propriedade de seu recurso quando construído ou movido, movendo-o, garantindo que o programador passe deliberadamente umstd::move(sourceObject)
ou um temporário, em vez de passar um lvalue e, de maneira não intuitiva / imprevisível, alterando-o por a tarefa de cópia ... que, como enfatizado aqui, era um problema centralauto_ptr
.A norma C ++ 03 (ISO-IEC 14882-2003) diz na cláusula 20.4.5, parágrafo 3:
A norma C ++ 11 (ISO-IEC 14882-2011) diz no apêndice D.10.1, parágrafo 3:
A norma C ++ 14 (ISO-IEC 14882-2014) diz no apêndice C.4.2 Anexo D: recursos de compatibilidade:
fonte