Vi tester et bibliotek under C ++ 11 (dvs. -std=c++11
). Biblioteket bruker auto_ptr
og dette mønsteret:
Foo* GetFoo() { autoptr<Foo> ptr(new Foo); // Initialize Foo ptr->Initialize(...); // Now configure remaining attributes ptr->SomeSetting(...); return ptr.release(); }
C ++ 11 utfaset auto_ptr
, så vi vil gå vekk fra det.
Koden støtter imidlertid både C ++ 03 og C ++ 11, så det er ikke så enkelt som å rive auto_ptr
. Det er også verdt å nevne at biblioteket ikke har noen eksterne avhengigheter. Det bruker C ++ 03, og bruker ikke Autotools, Cmake, Boost, …
Hvordan skal vi håndtere designendringene for å bevege oss bort fra auto_ptr
for C ++ 11 mens du beholder kompatibilitet med C ++ 03?
Kommentarer
Svar
I de fleste henseender ble std::unique_ptr
laget for å være drop in (men tryggere) erstatning for std::auto_ptr
, så det bør være svært få (hvis noen) kodeendringer som kreves annet enn (som du spør) dirigere koden til å bruke enten unique_ptr
eller auto_ptr
.
Det er noen måter å gjøre dette (og hver kommer med sine egne listeutvekslinger) nedenfor. Gitt koden som ble gitt, , vil jeg foretrekke en av de to første alternativene .
Alternativ 1
#if __cplusplus >= 201103L template <typename T> using auto_ptr = std::unique_ptr<T>; #else using std::auto_ptr; #endif
Avvik;
- Du introduserer
auto_ptr
navnet i det globale navneområdet ; Du kan redusere dette ved å definere at det er ditt eget " private " navneområde - Når du først migrerer til C ++ 17 (Jeg tror
auto_ptr
vil bli fjernet fullstendig) du kan lettere søke og erstatte
Alternativ 2
template <typename T> struct my_ptr { #if __cplusplus >= 201103L typedef std::unique_ptr<T> ptr; #else typedef std::auto_ptr<T> ptr; #endif };
Avvik;
- Sannsynligvis mer tungvint å jobbe med, alle gjeldende
auto_ptr
må endres i koden til noe sånt sommy_ptr<T>::ptr
- Bedre sikkerhet navnene blir ikke introdusert i det globale navneområdet
Alternativ 3
Noe kontroversielt, men hvis du er forberedt på å holde opp med advarslene om å ha 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
Avvik;
- Ikke prøv å bruke den arvede klassen der en virtuell base (spesielt med den ikke-virtuelle destruktoren) kan forventes. Ikke at dette skal være en saken i saken – men vær oppmerksom på det
- Igjen endres kode
- Potensielle feil i navneområdet – alt avhenger av hvordan pekeklassen brukes til å begynne med
Alternativ 4
Pakk inn pekerne i en ny klasse og samle de nødvendige funksjonene 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(); } };
Avvik;
- A lite ekstremt når alt du virkelig vil er å " bytte " implementeringene ut
Kommentarer
- Veldig bra svar. Jeg undersøkte det faktisk litt, og du traff minst tre av testene jeg prøvde. (Det du mangler er OS X og Clang-spesifikke ting. OS X er en bjørn fordi det til tider fortsatt bruker TR1-navneområdet for C ++ 03, og du må inkludere ting ved hjelp av denne metoden: Ingen type med navn ' unik_ptr ' i navneområdet ' std ' når du kompilerer under LLVM / Clang ).
- @jww. Jeg ' m på OS X (XCode 6.4 og Apple LLVM versjon 6.1.0 (clang-602.0.53) (basert på LLVM 3.6.0svn)) og har ingen problemer med C ++ 03/11-blanding annet enn
tr1
navneområdet ikke lenger er der (jeg bruker libc ++ og ikke libstdc ++).Jeg vet at tr1 ikke var normativ, men jeg kan ' ikke finne hvor som helst i utkastet (her) som filer måtte være<tr1/...>
i det hele tatt, infact det nevner bare å være i overskriften<memory>
etc.-filen bare itr1
navneområde. - @jww. Jeg antar at gitt en bestemt blanding av kompilator, bibliotek og målenhet – må du kanskje gjøre noen flere håndstativ. Ellers, på OS X, kan du vurdere å flytte til clang og libc ++. Helt ærlig anser jeg libc ++ for å være det nye " native " C ++ – biblioteket til OS X – det vil jeg som standard. Jeg har ingen måte å støtte disse påstandene andre om at historien til clang / Apple-forholdet og at GCC-verktøyene på OS X virker utdaterte (bibliotek) eller bare fjernet (så vidt jeg vet GCC er en tynn stub å klage uansett
- " Ellers vurderer du å flytte til clang og libc ++ på OS X … " – ja, jeg er ganske enig med deg. Vi vil imidlertid la brukerne ta det valget, og ikke tvinge det til dem. (De tar implisitt valget når de spesifiserer (eller mangler)
CXX=...
). - Her er ' saken som skaper meg så mye problemer på OS X 10.7 og 10.8:
c++ -v -std=c++11 -x c++ - < /dev/null
. Jeggrep'd
inkluderer katalogene som ble dumpet, og de inkluderer notunique_ptr
.
Svar
Alternativ 5: Direkte alias.
#if __cplusplus >= 201103L template<typename T> using MyPtr = std::unique_ptr<T>; #else #define MyPtr std::auto_ptr #endif
Avvik:
-
For nyere språkversjoner, AKA C ++ 11 og senere, tilordnes alias-typen til riktig smartpeker. Enhver brukerkode som faktisk er avhengig av API-er som er spesifikke for std :: auto_ptr, blir flagget av kompilatoren, noe som er den ultimate garantien for at den virkelig blir løst.
-
In Legacy c ++ 03-modus er typealiaset en makro. Dette er grovt, men den resulterende syntaksen
MyPtr<T>
vil være identisk med C ++ 11-saken i resten av koden. -
Du må finne og endre alle auto_ptr-variablene til
MyPtr
for å sette opp dette.
Kommentarer
- Det ' er veldig uklart hva dette refererer til (og som formulert, det er ikke ' et spørsmål i det hele tatt).
- @autophage Jeg tror det er et svar … så sannsynligvis ikke et spørsmål.
auto_ptr
scoped (dvs.std::auto_ptr
), må de være eller kan den smarte pekeren fås fra et annet navneområde?Foo::Initialize
tilFoo::Foo
.