Jak zacházet se změnami návrhu pro podporu auto_ptr v C ++ 11?

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

  • Je některý z oborů auto_ptr (tj. std::auto_ptr), musí být, nebo lze inteligentní ukazatel získat z nějakého jiného oboru názvů?
  • Kromě toho můžete chtít Foo::Initialize složit do Foo::Foo.
  • @ MSalters – ano, vždy to byla jedna z věcí, z nichž jsem se cítil trochu nepříjemně. Knihovna byla navržena v 90. letech a já si myslím design byl podobný MFC. To znamená, že tam byla nižší konstrukce na úrovni C ++ a poté " vyšší úroveň " konstrukce objektu. Myslím, že tato funkce byla použita jako kompromis, takže třídy don ' nemá 6 nebo 12 různých konstruktorů. (V tomto okamžiku jsem prošel a zajistil, aby členské proměnné typů POD byly inicializovány na rozumné výchozí hodnoty v konstruktorech C ++).

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 jako my_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 v tr1 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:

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

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

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

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *