Testăm o bibliotecă sub C ++ 11 (adică, -std=c++11
). Biblioteca utilizează auto_ptr
și acest model:
Foo* GetFoo() { autoptr<Foo> ptr(new Foo); // Initialize Foo ptr->Initialize(...); // Now configure remaining attributes ptr->SomeSetting(...); return ptr.release(); }
C ++ 11 depreciat auto_ptr
, așa că dorim să ne îndepărtăm de acesta.
Cu toate acestea, codul acceptă atât C ++ 03, cât și C ++ 11, deci nu este un simplu ca și divizarea auto_ptr
. De asemenea, merită menționat că biblioteca nu are dependențe externe. Folosește C ++ 03; și nu folosește Autotools, Cmake, Boost, …
Cum ar trebui să gestionăm modificările de proiectare pentru a ne îndepărta de la auto_ptr
pentru C ++ 11 păstrând în același timp compatibilitatea cu C ++ 03?
Comentarii
Răspuns
În cele mai multe privințe, std::unique_ptr
a fost introdus (dar mai sigur) înlocuire pentru std::auto_ptr
, deci ar trebui să existe foarte puține (dacă există) modificări de cod necesare, altele decât (după cum întrebați) direcționarea codului pentru a utiliza fie unique_ptr
, fie auto_ptr
.
Există câteva modalități de a face acest lucru (și fiecare vine cu propriile compromisuri ale listei) de mai jos. Având în vedere exemplul de cod furnizat, aș favoriza oricare dintre primele două opțiuni .
Opțiunea 1
#if __cplusplus >= 201103L template <typename T> using auto_ptr = std::unique_ptr<T>; #else using std::auto_ptr; #endif
Compensări;
- Introduceți numele
auto_ptr
în spațiul de nume global ; puteți atenua acest lucru definindu-l, este propriul dvs. spațiu de nume " privat " - După migrarea la C ++ 17 (Cred că
auto_ptr
va fi complet eliminat) puteți căuta și înlocui mai ușor
Opțiunea 2
template <typename T> struct my_ptr { #if __cplusplus >= 201103L typedef std::unique_ptr<T> ptr; #else typedef std::auto_ptr<T> ptr; #endif };
Compensări;
- Probabil mai greoaie pentru a lucra, toate
auto_ptr
curente trebuie schimbate în cod pentru ceva de genulmy_ptr<T>::ptr
- Siguranță mai bună, numele nu sunt introduse în spațiul de nume global
Opțiunea 3
Oarecum controversat, dar dacă sunteți pregătit să rezistați avertismentelor de a avea o clasă std
ca bază
#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
Compensări;
- Nu încercați să utilizați clasa moștenită unde ar fi de așteptat o bază virtuală (în special wrt destructorul non-virtual). Nu că aceasta ar trebui să fie o problemă în caz – dar fiți conștienți de aceasta
- Din nou, modificările de cod
- Potențiale nepotriviri ale spațiului de nume – totul depinde de modul în care este utilizată clasa indicatorului pentru a începe cu
Opțiunea 4
Înfășurați indicii într-o nouă clasă și agregați funcțiile necesare la membru
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(); } };
Compensări;
- A puțin extrem când tot ce îți dorești cu adevărat este să " să schimbi " implementările afară
Comentarii
- Răspuns foarte bun. De fapt, l-am cercetat puțin și ai dat cel puțin trei dintre testele pe care le-am încercat. (Ceea ce îți lipsește este lucrurile specifice OS X și Clang. OS X este un urs, deoarece folosește uneori încă spațiu de nume TR1 pentru C ++ 03 și trebuie să incluzi lucruri folosind această metodă: Niciun tip numit ' unique_ptr ' în spațiul de nume ' std ' atunci când compilați sub LLVM / Clang ).
- @jww. ' m pe OS X (XCode 6.4 și Apple LLVM versiunea 6.1.0 (clang-602.0.53) (bazat pe LLVM 3.6.0svn)) și nu am probleme cu C ++ 03/11 mix altele decât spațiul de nume
tr1
nu mai există (folosesc libc ++ și nu libstdc ++).Știu că tr1 a fost non-normativ, dar nu pot ' să găsesc oriunde în schița (aici) că fișierele trebuiau să fie<tr1/...>
deloc, de fapt menționează doar faptul că se află în antet<memory>
etc. fișier doar într1
spațiu de nume. - @jww. Cred că, având în vedere un anumit amestec de compilator, bibliotecă și dispozitiv țintă – poate fi necesar să mai faceți câteva suporturi manuale. Altfel, pe OS X, luați în considerare trecerea la clang și libc ++. Sincer, consider că libc ++ este noua " nativă " bibliotecă C ++ în OS X – aș prefera acest lucru. Nu am nicio modalitate de a susține aceste afirmații, altele că istoria relației clang / Apple și că instrumentele GCC din OS X par învechite (bibliotecă) sau pur și simplu eliminate (din câte știu, GCC este oricum un butuc subțire ).
- " Altfel, pe OS X, luați în considerare trecerea la clang și libc ++ … " – da, sunt cam de acord cu tine. Cu toate acestea, am dori să lăsăm utilizatorii să facă această alegere și să nu le impună. (Ei implicit fac alegerea atunci când specifică (sau lipsesc)
CXX=...
). - Aici ' este cazul asta îmi provoacă atât de multe probleme cu OS X 10.7 și 10.8:
c++ -v -std=c++11 -x c++ - < /dev/null
. Amgrep'd
directoarele de includere care au fost aruncate și nu includunique_ptr
.
Răspuns
Opțiunea 5: Alias direct.
#if __cplusplus >= 201103L template<typename T> using MyPtr = std::unique_ptr<T>; #else #define MyPtr std::auto_ptr #endif
Compensări:
-
Pentru versiunile lingvistice mai noi, AKA C ++ 11 și versiunile ulterioare, tipul de alias se mapează cu indicatorul inteligent corect. Orice cod de utilizator care depinde de fapt de API-urile specifice std :: auto_ptr va fi marcat de compilator, ceea ce reprezintă garanția finală că „va fi cu adevărat remediat.
-
În Legacy modul c ++ 03 aliasul de tip este o macro. Aceasta este brută, dar sintaxa rezultată
MyPtr<T>
va fi identică cu cazul C ++ 11 în restul codului. -
Trebuie să găsiți și să schimbați toate variabilele auto_ptr în
MyPtr
pentru a configura acest lucru.
Comentarii
- ' este foarte neclar la ce se referă acest lucru (și, așa cum este formulat, nu este deloc o ' o întrebare).
- @autophage Cred că este un răspuns … deci probabil că nu este o întrebare.
auto_ptr
(adicăstd::auto_ptr
), trebuie să fie sau pointerul inteligent poate fi obținut din alt spațiu de nume?Foo::Initialize
înFoo::Foo
.