Hvordan håndtere designendringer for auto_ptr avskrivning i C ++ 11?

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

  • Er noen av auto_ptr scoped (dvs. std::auto_ptr), må de være eller kan den smarte pekeren fås fra et annet navneområde?
  • Som en side til side kan det være lurt å brette Foo::Initialize til Foo::Foo.
  • @ MSalters – ja, det har alltid vært en av de tingene jeg har følt meg litt ukomfortabel med. Biblioteket ble designet på 1990-tallet, og jeg tror designet lignet på MFC. Det vil si at det var lavere nivå C ++ konstruksjon, og deretter en " høyere nivå " objektkonstruksjon. Jeg tror funksjonen ble brukt som en avveining så klassene ikke ' t har 6 eller 12 forskjellige konstruktører. (På dette punktet er det jeg har gjort gått gjennom og sørget for at medlemsvariablene til POD-typer blir initialisert til fornuftige standarder i C ++ -konstruktørene.

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 som my_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 i tr1 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. Jeg grep'd inkluderer katalogene som ble dumpet, og de inkluderer not unique_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:

  1. 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.

  2. 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.

  3. 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.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *