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
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 alsmy_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 hettr1
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
. Ikgrep'd
neem mappen op die zijn gedumpt, en ze bevatten nietunique_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:
-
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.
-
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. -
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.
auto_ptr
scoped (dwzstd::auto_ptr
), moeten ze zijn of kan de slimme aanwijzer worden verkregen uit een andere naamruimte?Foo::Initialize
inFoo::Foo
vouwen.