Як обробити зміни дизайну для депрекації auto_ptr в C ++ 11?


12

Ми тестуємо бібліотеку на C ++ 11 (тобто -std=c++11). Бібліотека використовує auto_ptrтаку схему:

Foo* GetFoo()
{
    autoptr<Foo> ptr(new Foo);

    // Initialize Foo
    ptr->Initialize(...);

    // Now configure remaining attributes
    ptr->SomeSetting(...);

    return ptr.release();
}

C ++ 11 застаріло auto_ptr, тому ми хочемо відійти від нього.

Однак код підтримує як C ++ 03, так і C ++ 11, тому його не так просто, як yanking auto_ptr. Також варто згадати, що бібліотека не має зовнішніх залежностей. Він використовує C ++ 03; і не використовує Autotools, Cmake, Boost, ...

Як нам впоратись із змінами дизайну, щоб відійти від auto_ptrC ++ 11, зберігаючи сумісність із C ++ 03?


Чи є який-небудь з auto_ptrобластей дії (тобто std::auto_ptr), чи вони повинні бути, чи інтелектуальний вказівник можна отримати з якогось іншого простору імен?
Найлл

Як і в сторону, ви можете згорнути Foo::Initializeв Foo::Foo.
MSalters

1
@MSalters - так, це завжди було однією з тих речей, з якими я відчував себе м'яко незручно. Бібліотека була розроблена в 90-х роках, і я думаю, що дизайн був схожий на MFC. Тобто, була конструкція нижчого рівня C ++, а потім будівництво об'єкта "вищого рівня". Я думаю, що ця функція була використана як компроміс, тому класи не мають 6 або 12 різних конструкторів. (На даний момент, що я зробив, я пройшов через і забезпечив ініціалізацію змінних членів типів POD для чистої настройки за замовчуванням у конструкторах C ++).

Відповіді:


13

У більшості аспектів це std::unique_ptrбуло зроблено для заміни (але більш безпечної) заміни std::auto_ptr, тому повинно бути дуже мало (якщо є) змін коду, необхідних, крім (як ви запитуєте) спрямування коду на використання unique_ptrабо auto_ptr.

Нижче є декілька способів зробити це (і кожен має свій власний список). Враховуючи зразок коду, що надається, я віддаю перевагу одному з перших двох варіантів .

Варіант 1

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

Компроміси;

  • Ви вводите auto_ptrім'я в глобальний простір імен; ви можете пом'якшити це, визначивши це власний "приватний" простір імен
  • Після переходу на C ++ 17 (я вважаю, auto_ptrбуде повністю видалено), ви можете легше шукати та замінювати

Варіант 2

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

Компроміси;

  • Напевно, більш громіздко працювати, всю поточну auto_ptrпотребу в коді змінити на щось подібнеmy_ptr<T>::ptr
  • Краща безпека імен не вводиться в глобальний простір імен

Варіант 3

Дещо суперечливий, але якщо ви готові миритися з застереженнями про те, що stdклас є базовим

#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

Компроміси;

  • Не намагайтеся використовувати успадкований клас там, де очікується віртуальна база (зокрема wrt невіртуальний деструктор). Мало того, що це має бути проблемою у справі - але пам’ятайте про це
  • Знову ж, зміни коду
  • Невідповідність потенційних просторів імен - все залежить від того, з чого використовується клас вказівника для початку

Варіант 4

Оберніть покажчики в новий клас і зберіть необхідні функції для члена

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

Компроміси;

  • Трохи крайність, коли все, що ти справді хочеш, - це "поміняти місцями" реалізації

Дуже гарна відповідь. Я насправді це трохи дослідив, і ти потрапив принаймні на три тести, які я пробував. (У вас бракує специфічних для OS X та Clang. OS X - ведмідь, оскільки вона все ще часом використовує простір імен TR1 для C ++ 03, і ​​вам доведеться включати речі за допомогою цього методу: у просторі імен немає типу "unique_ptr" 'std' під час компіляції під LLVM / Clang ).

@jww. Я перебуваю на OS X (XCode 6.4 та Apple LLVM версії 6.1.0 (clang-602.0.53) (на основі LLVM 3.6.0svn)) і не маю проблем із сумішшю C ++ 03/11, окрім tr1простори імен довше перебуваючи там (я використовую libc ++, а не libstdc ++). Я знаю, що tr1 був ненормативним, але я не можу знайти ніде в чернеті (тут), що файли повинні бути <tr1/...>взагалі, в інфакті він згадується просто у заголовку <memory>тощо. Файл просто в tr1просторі імен.
Найлл

@jww. Я здогадуюсь, що з огляду на певну комбінацію компілятора, бібліотеки та цільового пристрою - можливо, вам доведеться зробити ще кілька підстав для рук. В іншому випадку в OS X, розгляньте можливість переходу до clang та libc ++. Відверто кажучи, я вважаю, що libc ++ є новою "рідною" бібліотекою C ++ для OS X - я б замовчував це. У мене немає ніякого способу підтримати ці твердження, крім того, що історія стосунків кланг / Apple і що інструменти GCC на OS X здаються застарілими (бібліотека) або просто видалені (наскільки я знаю, GCC це тонка заглушка, яка б так само зачепилася) ).
Найлл

"Ще, в OS X, подумайте про перехід до clang та libc ++ ..." - так, я з вами згоден. Однак ми хочемо дозволити користувачам робити такий вибір, а не примушувати їх до себе. (Вони неявно роблять вибір, коли вони вказують (або відсутні) CXX=...).

Ось випадок , який викликає у мене стільки проблем на OS X 10.7 і 10.8: c++ -v -std=c++11 -x c++ - < /dev/null. Я grep'dвключаю каталоги, які були скинуті, і вони не включають unique_ptr.

0

Варіант 5: Прямий псевдонім.

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

Компроміси:

  1. Для новіших мовних версій AKA C ++ 11 та новіших версій ваш псевдонім вводить карти на правильний смарт-покажчик. Код користувача, який насправді залежить від API, специфічного для std :: auto_ptr, буде позначений компілятором, що є остаточною гарантією того, що він дійсно буде виправлений.

  2. У режимі Legacy c ++ 03 тип псевдонім макрос. Це грубо, але отриманий синтаксис MyPtr<T>буде ідентичним випадку C ++ 11 у всьому іншому коді.

  3. Ви повинні знайти та змінити всі свої змінні auto_ptr MyPtr, щоб налаштувати це.


1
Дуже незрозуміло, на що йдеться (і, як це висловлено, це зовсім не питання).
autophage

1
@autophage Я вважаю, що це відповідь ... так що, мабуть, не питання.
Kain0_0
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.