Testujeme knihovnu v jazyce C ++ 11 (tj. -std=c++11
). Knihovna používá auto_ptr
a tento vzor:
Foo* GetFoo() { autoptr<Foo> ptr(new Foo); // Initialize Foo ptr->Initialize(...); // Now configure remaining attributes ptr->SomeSetting(...); return ptr.release(); }
C ++ 11 zastaralé auto_ptr
, takže se od toho chceme vzdálit.
Kód však podporuje jak C ++ 03, tak C ++ 11, takže to není jednoduché jako trhání auto_ptr
. Za zmínku také stojí, že knihovna nemá žádné externí závislosti. Používá C ++ 03; a nepoužívá Autotools, Cmake, Boost, …
Jak bychom měli zvládnout změny designu, abychom se vzdálili z auto_ptr
pro C ++ 11 při zachování kompatibility s C ++ 03?
Komentáře
Odpověď
Ve většině ohledů byl std::unique_ptr
vytvořen jako drop-in (ale bezpečnější) náhrada za std::auto_ptr
, takže by mělo být zapotřebí jen velmi málo (pokud vůbec) jiných změn kódu než (jak se ptáte) nasměrování kódu k použití unique_ptr
nebo auto_ptr
.
Existuje několik způsobů, jak to udělat toto (a každý má své vlastní kompromisy se seznamem) níže. Vzhledem k uvedenému ukázce kódu bych upřednostňoval jednu z prvních dvou možností .
Možnost 1
#if __cplusplus >= 201103L template <typename T> using auto_ptr = std::unique_ptr<T>; #else using std::auto_ptr; #endif
Kompromisy;
- Název
auto_ptr
zavedete do globálního prostoru jmen ; můžete to zmírnit definováním, že se jedná o váš vlastní " soukromý " obor názvů - Jednou migrujte do C ++ 17 (Věřím, že
auto_ptr
bude zcela odstraněn) můžete snáze vyhledávat a nahrazovat
Možnost 2
template <typename T> struct my_ptr { #if __cplusplus >= 201103L typedef std::unique_ptr<T> ptr; #else typedef std::auto_ptr<T> ptr; #endif };
Kompromisy;
- Pravděpodobně těžkopádnější pro práci, všechny aktuální
auto_ptr
je třeba v kódu změnit na něco jakomy_ptr<T>::ptr
- Lepší bezpečnost, že se jména nezavádějí do globálního jmenného prostoru
Možnost 3
Trochu kontroverzní, ale pokud jste připraveni vyrovnat se s výhradami, že jako základnu budete mít std
třídu
#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
Kompromisy;
- Nezkoušejte použít zděděnou třídu, kde by se očekávala virtuální základna (zejména nevirtuální destruktor). Ne že by to mělo být problém v případě – ale uvědomte si to
- Opět platí, že změny kódu
- Nesoulad potenciálních oborů názvů – vše záleží na tom, jak je třída ukazatele na začátku použita
Možnost 4
Zabalte ukazatele do nové třídy a agregujte požadované funkce členovi
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(); } };
Kompromisy;
- A malý extrém, když vše, co opravdu chcete, je " vyměnit " implementace mimo
komentáře
- Velmi dobrá odpověď. Vlastně jsem to trochu prozkoumal a vy jste narazili alespoň na tři testy, které jsem zkoušel. (Co vám chybí, je OS X a Clang specifické věci. OS X je medvěd, protože občas stále používá jmenný prostor TR1 pro C ++ 03 a pomocí této metody musíte zahrnout věci: Žádný typ s názvem ' unique_ptr ' v oboru názvů ' std ' při kompilaci pod LLVM / Clang ).
- @jww. Jsem ' m na OS X (XCode 6.4 a Apple LLVM verze 6.1.0 (clang-602.0.53) (na základě LLVM 3.6.0svn)) a nemám problémy s C ++ 03/11 mix jiný než
tr1
obor názvů, který tam už není (používám libc ++ a ne libstdc ++).Vím, že tr1 nebyl normativní, ale ' nenajdu kdekoli v konceptu (zde) , že soubory musely být<tr1/...>
vůbec, infact zmiňuje to, že jsou právě v záhlaví<memory>
atd. souboru jen vtr1
jmenný prostor. - @jww. Myslím, že vzhledem ke konkrétní kombinaci kompilátoru, knihovny a cílového zařízení – možná budete muset udělat několik dalších stojek. Jinak v OS X zvažte přechod na clang a libc ++. Upřímně řečeno, považuji libc ++ za novou " nativní " knihovnu C ++ pro OS X – to bych standardně nastavil. Nemám žádný způsob, jak podpořit tato tvrzení, kromě toho, že historie vztahu clang / Apple a že nástroje GCC v OS X se zdají zastaralé (knihovna) nebo právě odstraněny (pokud vím, GCC je stejně tenký útržek ).
- " Jinak na OS X zvažte přechod na clang a libc ++ … " – ano, trochu s tebou souhlasím. Rádi bychom však umožnili uživatelům, aby se rozhodli, a nevynucovali jim to. (Implicitně se rozhodnou, když uvedou (nebo chybí)
CXX=...
). - Zde ' to mi v OS X 10.7 a 10.8 způsobuje tolik potíží:
c++ -v -std=c++11 -x c++ - < /dev/null
.grep'd
zahrnuji adresáře, které byly vypsány, a nejsou obsahujíunique_ptr
.
Odpověď
Možnost 5: Přímý alias.
#if __cplusplus >= 201103L template<typename T> using MyPtr = std::unique_ptr<T>; #else #define MyPtr std::auto_ptr #endif
Kompromisy:
-
U novějších jazykových verzí AKA C ++ 11 a novějších se váš aliasový typ mapuje na správný inteligentní ukazatel. Jakýkoli uživatelský kód, který ve skutečnosti závisí na API specifických pro std :: auto_ptr, bude označen kompilátorem, což je nejvyšší záruka, že bude skutečně opraven.
-
Ve starší verzi V režimu c ++ 03 je alias typu makro. Toto je hrubé, ale výsledná syntaxe
MyPtr<T>
bude po zbytek kódu identická s případem C ++ 11. -
Chcete-li to nastavit, musíte najít a změnit všechny své proměnné auto_ptr na
MyPtr
.
Komentáře
- Je ' velmi nejasné, na co to odkazuje (a jak je formulováno, to vůbec není ' ta otázka).
- @autophage Věřím, že je to odpověď … takže pravděpodobně ne otázka.
auto_ptr
(tj.std::auto_ptr
), musí být, nebo lze inteligentní ukazatel získat z nějakého jiného oboru názvů?Foo::Initialize
složit doFoo::Foo
.