Comment gérer les modifications de conception pour la dépréciation auto_ptr dans C ++ 11?

Nous testons une bibliothèque sous C ++ 11 (cest-à-dire -std=c++11). La bibliothèque utilise auto_ptr et ce modèle:

Foo* GetFoo() { autoptr<Foo> ptr(new Foo); // Initialize Foo ptr->Initialize(...); // Now configure remaining attributes ptr->SomeSetting(...); return ptr.release(); } 

C ++ 11 obsolète auto_ptr, nous voulons donc nous en éloigner.

Cependant, le code prend en charge à la fois C ++ 03 et C ++ 11, donc ce nest pas aussi simple que de tirer auto_ptr. Il est également intéressant de mentionner que la bibliothèque na pas de dépendances externes. Elle utilise C ++ 03; et nutilise pas Autotools, Cmake, Boost, …

Comment devons-nous gérer les changements de conception pour séloigner de auto_ptr pour C ++ 11 tout en conservant la compatibilité avec C ++ 03?

Commentaires

  • Certains des auto_ptr ont-ils une portée (cest-à-dire std::auto_ptr), doivent-ils lêtre ou le pointeur intelligent peut-il être obtenu à partir dun autre espace de noms?
  • En passant, vous pouvez replier Foo::Initialize en Foo::Foo.
  • @ MSalters – oui, cela a toujours été lune de ces choses pour lesquelles je me suis senti un peu mal à laise. La bibliothèque a été conçue dans les années 1990 et je pense que la conception était similaire à celle de MFC. Autrement dit, il y avait moins construction de niveau C ++, puis une construction dobjet " de niveau supérieur ". Je pense que la fonctionnalité a été utilisée comme un compromis afin que les classes ne ' t ont 6 ou 12 constructeurs différents. (À ce stade, ce que jai fait est passé en revue et sest assuré que les variables membres des types POD sont initialisées avec des valeurs par défaut saines dans les constructeurs C ++).

Réponse

À bien des égards, le std::unique_ptr a été conçu pour être ajouté (mais plus sûr) remplacement de std::auto_ptr , il ne devrait donc y avoir que très peu de changements de code (le cas échéant) autres que (comme vous le demandez) en dirigeant le code pour quil utilise soit unique_ptr soit auto_ptr.

Il existe plusieurs façons de procéder ceci (et chacun vient avec sa propre liste de compromis) ci-dessous. Compte tenu de lexemple de code fourni, je préférerais lune des deux premières options .

Option 1

#if __cplusplus >= 201103L template <typename T> using auto_ptr = std::unique_ptr<T>; #else using std::auto_ptr; #endif 

Compromis;

  • Vous introduisez le nom auto_ptr dans lespace de noms global ; vous pouvez atténuer ce problème en définissant quil sagit de votre propre espace de noms " private "
  • Une fois migré vers C ++ 17 (Je pense que auto_ptr sera complètement supprimé) vous pouvez rechercher et remplacer plus facilement

Option 2

template <typename T> struct my_ptr { #if __cplusplus >= 201103L typedef std::unique_ptr<T> ptr; #else typedef std::auto_ptr<T> ptr; #endif }; 

Compromis;

  • Probablement plus compliqué à travailler, tous les auto_ptr actuels doivent être modifiés dans le code en quelque chose comme my_ptr<T>::ptr
  • Plus de sécurité, les noms ne sont pas introduits dans lespace de noms global

Option 3

Un peu controversé, mais si vous êtes prêt à accepter la mise en garde davoir une classe std comme 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 

Compromis;

  • Nessayez pas dutiliser la classe héritée là où une base virtuelle (en particulier avec le destructeur non virtuel) serait attendue. Non pas que cela devrait être un problème dans laffaire – mais sachez-le
  • Encore une fois, le code change
  • Différences potentielles despace de noms – tout dépend de la façon dont la classe de pointeur est utilisée pour commencer par

Option 4

Enveloppez les pointeurs dans une nouvelle classe et agrégez les fonctions requises au membre

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(); } }; 

Compromis;

  • A petit extrême quand tout ce que vous voulez vraiment est de " swap " les implémentations en dehors

Commentaires

  • Très bonne réponse. En fait, je lai fait un peu de recherche et vous avez réussi au moins trois des tests que jai essayés. (Ce qui vous manque, ce sont les éléments spécifiques à OS X et à Clang. OS X est un ours car il utilise encore parfois lespace de noms TR1 pour C ++ 03, et vous devez inclure des éléments en utilisant cette méthode: Aucun type nommé ' unique_ptr ' dans lespace de noms ' std ' lors de la compilation sous LLVM / Clang ).
  • @jww. Je ' m sous OS X (XCode 6.4 et Apple LLVM version 6.1.0 (clang-602.0.53) (basé sur LLVM 3.6.0svn)) et nai aucun problème avec le C ++ 03/11 mix autre que lespace de noms tr1 nétant plus là (jutilise libc ++ et non libstdc ++).Je sais que tr1 nétait pas normatif, mais je ne peux ' trouver nulle part dans le brouillon (ici) que le les fichiers devaient être <tr1/...> du tout, en fait, il mentionne simplement être dans len-tête <memory> etc. fichier juste dans le tr1 espace de noms.
  • @jww. Je suppose que, étant donné un mélange particulier de compilateur, de bibliothèque et de périphérique cible, vous devrez peut-être faire quelques supports supplémentaires. Sinon, sous OS X, envisagez de passer à clang et libc ++. Franchement, je considère que la libc ++ est la nouvelle bibliothèque C ++ " native " pour OS X – je le ferais par défaut. Je nai aucun moyen de soutenir ces affirmations autres que lhistoire de la relation clang / Apple et que les outils GCC sur OS X semblent obsolètes (bibliothèque) ou simplement supprimés (pour autant que je sache, GCC est un mince bout à cliqueter de toute façon ).
  • " Sinon, sous OS X, envisagez de passer à clang et libc ++ … " – ouais, je suis plutôt daccord avec vous. Cependant, nous aimerions laisser les utilisateurs faire ce choix et ne pas le leur imposer. (Ils font implicitement le choix lorsquils spécifient (ou manquent) de CXX=...).
  • Ici ' cest le cas cela me cause tellement de problèmes sur OS X 10.7 et 10.8: c++ -v -std=c++11 -x c++ - < /dev/null. Je grep'd les répertoires dinclusion qui ont été vidés, et ils nincluent pas unique_ptr.

Réponse

Option 5: Alias direct.

#if __cplusplus >= 201103L template<typename T> using MyPtr = std::unique_ptr<T>; #else #define MyPtr std::auto_ptr #endif 

Compromis:

  1. Pour les versions linguistiques plus récentes, AKA C ++ 11 et versions ultérieures, votre type dalias correspond au pointeur intelligent approprié. Tout code utilisateur qui dépend en fait dAPI spécifiques à std :: auto_ptr sera signalé par le compilateur, ce qui est la garantie ultime quil « sera vraiment corrigé.

  2. In Legacy Mode c ++ 03, lalias de type est une macro. Cest grossier, mais la syntaxe résultante MyPtr<T> sera identique au cas C ++ 11 dans le reste du code.

  3. Vous devez trouver et changer toutes vos variables auto_ptr en MyPtr pour configurer cela.

Commentaires

  • Il ' nest pas clair de quoi il sagit (et, comme formulé, ce nest pas ' une question).
  • @autophage Je crois que cest une réponse … donc probablement pas une question.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *