Hoe om te gaan met ontwerpwijzigingen voor auto_ptr-deprecatie in C ++ 11?

We testen een bibliotheek onder C ++ 11 (d.w.z. -std=c++11). De bibliotheek gebruikt auto_ptr en dit patroon:

Foo* GetFoo() { autoptr<Foo> ptr(new Foo); // Initialize Foo ptr->Initialize(...); // Now configure remaining attributes ptr->SomeSetting(...); return ptr.release(); } 

C ++ 11 verouderd auto_ptr, dus we willen er afstand van nemen.

De code ondersteunt echter zowel C ++ 03 als C ++ 11, dus het is niet zo simpel als het rukken van auto_ptr. Het is ook de moeite waard te vermelden dat de bibliotheek geen externe afhankelijkheden heeft. Het gebruikt C ++ 03; en maakt geen gebruik van Autotools, Cmake, Boost, …

Hoe moeten we omgaan met de ontwerpwijzigingen om weg te gaan van auto_ptr voor C ++ 11 met behoud van compatibiliteit met C ++ 03?

Reacties

  • Zijn een van de auto_ptr scoped (dwz std::auto_ptr), moeten ze zijn of kan de slimme aanwijzer worden verkregen uit een andere naamruimte?
  • Even terzijde: misschien wil je Foo::Initialize in Foo::Foo vouwen.
  • @ MSalters – ja, dat is altijd een van die dingen geweest waar ik me enigszins ongemakkelijk bij voelde. De bibliotheek is ontworpen in de jaren negentig en ik denk dat het ontwerp vergelijkbaar was met die van MFC. Dat wil zeggen, er was minder niveau C ++ constructie, en vervolgens een " hoger niveau " objectconstructie. Ik denk dat de functie werd gebruikt als een afweging, dus klassen don ' t hebben 6 of 12 verschillende constructors. (Op dit punt is wat ik heb gedaan doorgenomen en ervoor gezorgd dat de lidvariabelen van POD-typen worden geïnitialiseerd naar normale standaardwaarden in de C ++ constructors).

Antwoord

In de meeste opzichten is de std::unique_ptr gemaakt om in te zetten (maar veiliger) vervanging voor std::auto_ptr , dus er zouden zeer weinig (indien van toepassing) codewijzigingen moeten zijn, behalve (zoals je vraagt) de code opdracht geven om ofwel unique_ptr of auto_ptr te gebruiken.

Er zijn een paar manieren om dit te doen dit (en elk heeft zijn eigen afwegingen) hieronder. Gezien het verstrekte codevoorbeeld zou ik de voorkeur geven aan een van de eerste twee opties .

Optie 1

#if __cplusplus >= 201103L template <typename T> using auto_ptr = std::unique_ptr<T>; #else using std::auto_ptr; #endif 

Afwegingen;

  • Je introduceert de auto_ptr naam in de globale naamruimte ; u kunt dit verminderen door te definiëren dat het uw eigen " private " naamruimte is
  • Eenmaal migreren naar C ++ 17 (Ik denk dat auto_ptr volledig zal worden verwijderd) u kunt gemakkelijker zoeken en vervangen

Optie 2

template <typename T> struct my_ptr { #if __cplusplus >= 201103L typedef std::unique_ptr<T> ptr; #else typedef std::auto_ptr<T> ptr; #endif }; 

Afwegingen;

  • Waarschijnlijk lastiger om mee te werken, alle huidige auto_ptr moeten in de code worden gewijzigd in zoiets als my_ptr<T>::ptr
  • Betere veiligheid, de namen worden niet geïntroduceerd in de globale naamruimte

Optie 3

Enigszins controversieel, maar als je bereid bent om de voorbehouden te accepteren van het hebben van een std klasse als basis

#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 

Afwegingen;

  • Probeer niet de overgeërfde klasse te gebruiken waar een virtuele basis (in het bijzonder met betrekking tot de niet-virtuele destructor) zou worden verwacht. Niet dat dit een probleem in het geval – maar wees je ervan bewust
  • Nogmaals, codewijzigingen
  • Potentiële naamruimte komt niet overeen – het hangt allemaal af van hoe de pointer class wordt gebruikt om mee te beginnen

Optie 4

Verpak de verwijzingen in een nieuwe klasse en voeg de vereiste functies toe aan het lid

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(); } }; 

Afwegingen;

  • A beetje extreem als je alleen maar " " de implementaties wilt verwisselen

Reacties

  • Zeer goed antwoord. Ik heb het eigenlijk een beetje onderzocht, en je hebt ten minste drie van de tests gehaald die ik heb geprobeerd. (Wat je mist zijn de OS X- en Clang-specifieke dingen. OS X is een beer omdat het soms nog steeds TR1-naamruimte gebruikt voor C ++ 03, en je moet dingen opnemen met behulp van deze methode: Geen type met de naam ' unique_ptr ' in naamruimte ' std ' bij het compileren onder LLVM / Clang ).
  • @jww. Ik ' m op OS X (XCode 6.4 en Apple LLVM versie 6.1.0 (clang-602.0.53) (gebaseerd op LLVM 3.6.0svn)) en heb geen problemen met de C ++ 03/11 mix anders dan de tr1 naamruimte is er niet meer (ik gebruik wel libc ++ en niet libstdc ++).Ik weet dat tr1 niet normatief was, maar ik kan ' nergens in het concept (hier) vinden dat de bestanden moesten überhaupt <tr1/...> zijn, het vermeldt feitelijk dat ze alleen in de header <memory> etc. staan, alleen in het tr1 naamruimte.
  • @jww. Ik denk dat, gezien een bepaalde mix van compiler, bibliotheek en doelapparaat, je misschien nog een paar handstandaarden moet doen. Anders, in OS X, overweeg om over te stappen naar clang en libc ++. Eerlijk gezegd beschouw ik de libc ++ als de nieuwe " native " C ++ -bibliotheek naar OS X – dat zou ik standaard doen. Ik kan deze beweringen niet ondersteunen, behalve dat de geschiedenis van de clang / Apple-relatie en dat de GCC-tools op OS X verouderd lijken (bibliotheek) of gewoon zijn verwijderd (voor zover ik weet is GCC een dunne stomp om toch te klinken ).
  • " Overweeg in OS X over te stappen naar clang en libc ++ … " – ja, ik ben het met je eens. We willen de gebruikers echter die keuze laten maken, en ze niet opdringen. (Ze maken impliciet de keuze wanneer ze CXX=... specificeren (of ontbreken).
  • Hier is ' het geval dat bezorgt me zoveel problemen op OS X 10.7 en 10.8: c++ -v -std=c++11 -x c++ - < /dev/null. Ik grep'd neem mappen op die zijn gedumpt, en ze bevatten niet unique_ptr.

Antwoord

Optie 5: Directe alias.

#if __cplusplus >= 201103L template<typename T> using MyPtr = std::unique_ptr<T>; #else #define MyPtr std::auto_ptr #endif 

Afwegingen:

  1. Voor nieuwere taalversies, AKA C ++ 11 en later, wijst je aliastype toe aan de juiste slimme aanwijzer. Elke gebruikerscode die eigenlijk afhankelijk is van APIs die specifiek zijn voor std :: auto_ptr, wordt gemarkeerd door de compiler, wat de ultieme garantie is dat deze “echt zal worden hersteld.

  2. In Legacy c ++ 03-modus het type alias is een macro. Dit is grof, maar de resulterende syntaxis MyPtr<T> zal in de rest van de code identiek zijn aan het geval van C ++ 11.

  3. Je moet al je auto_ptr-variabelen vinden en wijzigen in MyPtr om dit in te stellen.

Reacties

  • Het ' is erg onduidelijk waar dit naar verwijst (en, zoals gezegd, het is helemaal geen ' een vraag).
  • @autophage Ik geloof dat het een antwoord is … dus waarschijnlijk geen vraag.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *