Vi tester et bibliotek under C ++ 11 (dvs. -std=c++11
). Biblioteket bruger auto_ptr
og dette mønster:
Foo* GetFoo() { autoptr<Foo> ptr(new Foo); // Initialize Foo ptr->Initialize(...); // Now configure remaining attributes ptr->SomeSetting(...); return ptr.release(); }
C ++ 11 forældet auto_ptr
, så vi vil bevæge os væk fra det.
Koden understøtter dog både C ++ 03 og C ++ 11, så det er ikke så simpelt som at rykke auto_ptr
. Det er også værd at nævne, at biblioteket ikke har nogen eksterne afhængigheder. Det bruger C ++ 03 og bruger ikke Autotools, Cmake, Boost, …
Hvordan skal vi håndtere designændringerne for at bevæge os væk fra auto_ptr
til C ++ 11, mens kompatibilitet med C ++ 03 bevares?
Kommentarer
Svar
I de fleste henseender blev std::unique_ptr
lavet til drop in (men sikrere) erstatning for std::auto_ptr
, så der skulle være meget få (hvis nogen) kodeændringer, der kræves bortset fra (som du spørger) dirigerer koden til at bruge enten unique_ptr
eller auto_ptr
.
Der er et par måder at gøre dette (og hver kommer med sine egne listekompromiser) nedenfor. I betragtning af den angivne kodeeksempel vil jeg foretrække en af de to første muligheder .
Mulighed 1
#if __cplusplus >= 201103L template <typename T> using auto_ptr = std::unique_ptr<T>; #else using std::auto_ptr; #endif
Afvejninger;
- Du introducerer
auto_ptr
navnet i det globale navneområde ; du kan afbøde dette ved at definere, at det er dit eget " private " navneområde - Når du først migrerer til C ++ 17 (Jeg tror
auto_ptr
fjernes fuldstændigt) du kan lettere søge og erstatte
Mulighed 2
template <typename T> struct my_ptr { #if __cplusplus >= 201103L typedef std::unique_ptr<T> ptr; #else typedef std::auto_ptr<T> ptr; #endif };
Tradeoffs;
- Sandsynligvis mere besværligt at arbejde med, alt det aktuelle
auto_ptr
skal ændres i koden til noget sommy_ptr<T>::ptr
- Bedre sikkerhed navnene introduceres ikke i det globale navneområde
Mulighed 3
Noget kontroversielt, men hvis du er parat til at udholde advarslerne om at have en std
klasse som 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
Kompromiser;
- Forsøg ikke at bruge den nedarvede klasse, hvor en virtuel base (især med den ikke-virtuelle destruktor) forventes. Ikke at dette skulle være en problem i sagen – men vær opmærksom på det
- Igen ændrer kode
- Potentielle navneområde-uoverensstemmelser – alt afhænger af, hvordan pointerklassen bruges til at begynde med
Mulighed 4
Sæt markørerne i en ny klasse, og saml de nødvendige funktioner til medlemmet
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(); } };
Afvejninger;
- A lidt ekstrem, når alt hvad du virkelig vil, er at " bytte " implementeringerne ud
Kommentarer
- Meget godt svar. Jeg undersøgte det faktisk lidt, og du ramte mindst tre af de test, jeg prøvede. (Hvad du mangler er OS X og Clang-specifikke ting. OS X er en bjørn, fordi det stadig bruger TR1 navneområde til C ++ 03 til tider, og du skal medtage ting ved hjælp af denne metode: Ingen type med navnet ' unik_ptr ' i navneområdet ' std ' ved kompilering under LLVM / Clang ).
- @jww. I ' m på OS X (XCode 6.4 og Apple LLVM version 6.1.0 (clang-602.0.53) (baseret på LLVM 3.6.0svn)) og har ingen problemer med C ++ 03/11-mix bortset fra
tr1
navneområdet ikke længere er der (jeg bruger libc ++ og ikke libstdc ++).Jeg ved, at tr1 ikke var normativ, men jeg kan ' ikke finde nogen steder i kladden (her) som filer skulle overhovedet være<tr1/...>
, infact nævner det bare at være i overskriften<memory>
osv. bare itr1
navneområde. - @jww. Jeg antager, at i betragtning af en bestemt blanding af kompilator, bibliotek og målenhed – skal du muligvis lave et par flere håndstande. Ellers kan du overveje at flytte til clang og libc ++ på OS X. Helt ærligt anser jeg libc ++ for at være det nye " native " C ++ – bibliotek til OS X – det ville jeg som standard. Jeg har ingen måde at støtte disse påstande på, at historien om clang / Apple-forholdet og at GCC-værktøjerne på OS X ser ud til at være forældede (bibliotek) eller bare er fjernet (så vidt jeg ved, er GCC alligevel en tynd stub
- " Ellers kan du i OS X overveje at flytte til clang og libc ++ … " – ja, jeg er lidt enig med dig. Vi vil dog gerne lade brugerne træffe dette valg og ikke tvinge det til dem. (De træffer implicit valget, når de angiver (eller mangler)
CXX=...
). - Her er ' sagen det skaber mig så mange problemer på OS X 10.7 og 10.8:
c++ -v -std=c++11 -x c++ - < /dev/null
. Jeggrep'd
inkluderer mapper, der blev dumpet, og de not inkludererunique_ptr
.
Svar
Mulighed 5: Direkte alias.
#if __cplusplus >= 201103L template<typename T> using MyPtr = std::unique_ptr<T>; #else #define MyPtr std::auto_ptr #endif
Kompromiser:
-
For nyere sprogversioner, AKA C ++ 11 og senere, tilordnes din alias-type til den rigtige smarte pointer. Enhver brugerkode, der faktisk afhænger af APIer, der er specifikke for std :: auto_ptr, bliver markeret af compileren, hvilket er den ultimative garanti for, at den virkelig bliver rettet.
-
In Legacy c ++ 03-tilstand er typealiaset en makro. Dette er groft, men den resulterende syntaks
MyPtr<T>
vil være identisk med C ++ 11-sagen i resten af koden. -
Du skal finde og ændre alle dine auto_ptr-variabler til
MyPtr
for at konfigurere dette.
Kommentarer
- Det ' er meget uklart, hvad dette henviser til (og som formuleret, det er ' overhovedet et spørgsmål).
- @autophage Jeg tror, det er et svar … så sandsynligvis ikke et spørgsmål.
auto_ptr
scoped (dvs.std::auto_ptr
), skal de være, eller kan den smarte markør fås fra et andet navneområde?Foo::Initialize
tilFoo::Foo
.