Hvordan håndteres designændringer for auto_ptr-afskrivning i C ++ 11?

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

  • Er nogen af auto_ptr scoped (dvs. std::auto_ptr), skal de være, eller kan den smarte markør fås fra et andet navneområde?
  • Som en sidebemærkning vil du måske folde Foo::Initialize til Foo::Foo.
  • @ MSalters – ja, det har altid været en af de ting, jeg har følt mig let ubehagelig over. Biblioteket blev designet i 1990erne, og jeg synes designet lignede MFC. Det vil sige, der var lavere niveau C ++ konstruktion, og derefter en " højere niveau " objektkonstruktion. Jeg tror, at funktionen blev brugt som en kompromis, så klasser ikke ' t har 6 eller 12 forskellige konstruktører. (På dette tidspunkt er det, jeg har gjort, gået igennem og sikret, at medlemsvariablerne for POD-typer initialiseres til fornuftige standarder i C ++ – konstruktørerne.

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

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

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

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

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *