Estamos testando uma biblioteca em C ++ 11 (ou seja, -std=c++11
). A biblioteca usa auto_ptr
e este padrão:
Foo* GetFoo() { autoptr<Foo> ptr(new Foo); // Initialize Foo ptr->Initialize(...); // Now configure remaining attributes ptr->SomeSetting(...); return ptr.release(); }
C ++ 11 obsoleto auto_ptr
, então queremos nos afastar disso.
No entanto, o código suporta C ++ 03 e C ++ 11, portanto, não é tão simples quanto arrancar auto_ptr
. Também vale a pena mencionar que a biblioteca não tem dependências externas. Ela usa C ++ 03; e não usa Autotools, Cmake, Boost, …
Como devemos lidar com as mudanças de design para sair de auto_ptr
para C ++ 11 enquanto mantém a compatibilidade com C ++ 03?
Comentários
Resposta
Na maioria dos aspectos, o std::unique_ptr
foi feito para ser entregue (mas mais seguro) substituição para std::auto_ptr
, então deve haver muito poucas (se houver) alterações de código necessárias além (como você pede) direcionando o código para usar unique_ptr
ou auto_ptr
.
Existem algumas maneiras de fazer isso (e cada um vem com suas próprias compensações de lista) abaixo. Dado o exemplo de código fornecido, Eu preferiria qualquer uma das duas primeiras opções .
Opção 1
#if __cplusplus >= 201103L template <typename T> using auto_ptr = std::unique_ptr<T>; #else using std::auto_ptr; #endif
Trocas;
- Você introduz o nome
auto_ptr
no namespace global ; você pode atenuar isso definindo que é seu próprio " privado " namespace - Depois de migrar para C ++ 17 (Eu acredito que
auto_ptr
será completamente removido) você pode pesquisar e substituir mais facilmente
Opção 2
template <typename T> struct my_ptr { #if __cplusplus >= 201103L typedef std::unique_ptr<T> ptr; #else typedef std::auto_ptr<T> ptr; #endif };
Compensações;
- Provavelmente mais complicado de se trabalhar, todas as
auto_ptr
atuais precisam ser alteradas no código para algo comomy_ptr<T>::ptr
- Melhor segurança porque os nomes não estão sendo introduzidos no namespace global
Opção 3
Um pouco controverso, mas se você estiver preparado para tolerar as advertências de ter uma std
classe como base
#if __cplusplus >= 201103L template <typename T> using my_ptr = std::unique_ptr<T>; #else template <typename T> class my_ptr : public std::auto_ptr<T> { // implement the constructors for easier use // in particular explicit my_ptr( X* p = 0 ) : std::auto_ptr(p) {} }; #endif
Tradeoffs;
- Não tente usar a classe herdada onde uma base virtual (em particular, o destruidor não virtual) seria esperada. Não que isso deva ser um problema no caso – mas esteja ciente disso
- Novamente, alterações de código
- Possíveis incompatibilidades de namespace – tudo depende de como a classe de ponteiro é usada para começar
Opção 4
Envolva os ponteiros em uma nova classe e agregue as funções necessárias ao membro
template <typename T> class my_ptr { // could even use auto_ptr name? #if __cplusplus >= 201103L std::unique_ptr<T> ptr_; #else std::auto_ptr<T> ptr_; #endif // implement functions required... T* release() { return ptr_.release(); } };
Trocas;
- A um pouco extremo quando tudo o que você realmente deseja é " trocar " as implementações fora
Comentários
- Muito boa resposta. Na verdade, pesquisei um pouco e você acertou pelo menos três dos testes que tentei. (O que falta são as coisas específicas do OS X e do Clang. OS X é um urso porque às vezes ainda usa o namespace TR1 para C ++ 03, e você deve incluir coisas usando este método: Nenhum tipo denominado ' unique_ptr ' no namespace ' std ' ao compilar em LLVM / Clang ).
- @jww. I ' m no OS X (XCode 6.4 e Apple LLVM versão 6.1.0 (clang-602.0.53) (baseado no LLVM 3.6.0svn)) e não tenho problemas com o C ++ 03/11 mix diferente do
tr1
namespace não existe mais (eu uso libc ++ e não libstdc ++).Eu sei que tr1 não era normativo, mas não posso ' encontrar em qualquer lugar do rascunho (aqui) que o os arquivos precisavam ser<tr1/...>
, na verdade, ele menciona apenas estar no cabeçalho<memory>
etc. arquivo apenas notr1
namespace. - @jww. Eu acho que dada uma combinação particular de compilador, biblioteca e dispositivo de destino – você pode precisar fazer mais alguns suportes manuais. Caso contrário, no OS X, considere mudar para clang e libc ++. Sinceramente, considero a libc ++ a nova " nativa " biblioteca C ++ para OS X – isso seria o padrão. Não tenho como apoiar essas afirmações de que a história do relacionamento clang / Apple e que as ferramentas do GCC no OS X parecem desatualizadas (biblioteca) ou apenas removidas (pelo que eu sei o GCC é um toco para clang de qualquer maneira ).
- " Caso contrário, no OS X, considere mudar para clang e libc ++ … " – sim, eu meio que concordo com você. No entanto, gostaríamos de permitir que os usuários façam essa escolha, e não forçá-los. (Eles implicitamente fazem a escolha quando especificam (ou faltam)
CXX=...
). - Aqui ' é o caso isso está me causando tantos problemas no OS X 10.7 e 10.8:
c++ -v -std=c++11 -x c++ - < /dev/null
. Eugrep'd
os diretórios incluídos que foram despejados, e eles não incluemunique_ptr
.
Resposta
Opção 5: alias direto.
#if __cplusplus >= 201103L template<typename T> using MyPtr = std::unique_ptr<T>; #else #define MyPtr std::auto_ptr #endif
Trocas:
-
Para versões de idioma mais recentes, também conhecido como C ++ 11 e posterior, seu tipo de alias mapeia para o ponteiro inteligente correto. Qualquer código de usuário que realmente dependa de APIs específicas para std :: auto_ptr será sinalizado pelo compilador, o que é a garantia definitiva de que “será realmente corrigido.
-
No Legacy No modo c ++ 03, o alias do tipo é uma macro. Isso é bruto, mas a sintaxe resultante
MyPtr<T>
será idêntica ao caso C ++ 11 em todo o resto do código. -
Você deve encontrar e alterar todas as suas variáveis auto_ptr para
MyPtr
para configurar isso.
Comentários
- ' é muito obscuro o que isso está referenciando (e, como expresso, não é ' uma pergunta).
- @autophage Acredito que seja uma resposta … então provavelmente não é uma pergunta.
auto_ptr
escopo (isto é,std::auto_ptr
), eles precisam ser ou o ponteiro inteligente pode ser obtido de algum outro namespace?Foo::Initialize
emFoo::Foo
.