используя (или другой механизм) для замены unique_ptr на auto_ptr в С++ 11?

Я получаю предупреждение о компиляции под Cygwin с помощью -std=c++11:

cryptlib.cpp: In member function ‘virtual size_t PK_Signer::SignMessage(RandomNumberGenerator&, const byte*, size_t, byte*) const’:
cryptlib.cpp:770:41: warning: ‘auto_ptr’ is deprecated (declared at /usr/lib/gcc/x86_64-pc-cygwin/4.9.3/include/c++/backward/auto_ptr.h:87) [-Wdeprecated-declarations]
std::auto_ptr<PK_MessageAccumulator> m(NewSignatureAccumulator(rng));
                                       ^

Я попытался добавить:

#if defined(MYLIB_CXX11)
using auto_ptr = std::unique_ptr;
#else
using std::auto_ptr;
#endif

auto_ptr<PK_MessageAccumulator> m(NewSignatureAccumulator(rng));

Но это привело к следующему, даже с включенным <memory>.

$ make cryptlib.o 
c++ -std=c++11 -DNDEBUG -g2 -O3 -fPIC -march=native -DCRYPTOPP_DISABLE_ASM -Wall -Wextra -pipe -c cryptlib.cpp
cryptlib.cpp:770:27: error: no type named 'unique_ptr' in namespace 'std'
    using auto_ptr = std::unique_ptr;
                     ~~~~~^

Я также пробовал варианты следующего:

#if defined(MYLIB_CXX11)
typedef std::unique_ptr<T> local_ptr<T>;
#else
typedef std::auto_ptr local_ptr;
#endif

Я не могу сделать чистый переход на unique_ptr, потому что это библиотека C++03, а в C++03 отсутствует unique_ptr. И я не могу допустить, чтобы грязная компиляция продолжалась под C++11, потому что чистая компиляция — это ворота безопасности, а управление не позволит библиотеке пройти. (Об предупреждающих трюках не может быть и речи, потому что это должно быть простым, низко висящим фруктом. Предупреждающие трюки включают в себя отключение предупреждения).

Можно ли использовать "using" для замены unique_ptr? Или есть какой-то другой механизм?


person jww    schedule 27.07.2015    source источник
comment
Если код находится под вашим контролем, можно ли его перекомпилировать, учитывая, что С++ 03 против С++ 11 поддерживает ваши требования? Смотрите мое обновление ниже.   -  person Niall    schedule 27.07.2015
comment
Ваши определения типов не работают, потому что они относятся к шаблонам, а не к типам. Однако вы можете сделать это очень похожим образом, см. Мой ответ.   -  person Walter    schedule 27.07.2015


Ответы (3)


Понимая, что код находится под вашим контролем и может быть перекомпилирован с поддержкой C++11 или без нее, можно создать псевдоним для требуемого интеллектуального указателя (либо std::unique_ptr, либо std::auto_ptr).

template <typename T>
struct local_ptr {
    #if defined(MYLIB_CXX11)
    typedef std::unique_ptr<T> ptr;
    #else
    typedef std::auto_ptr<T> ptr;
    #endif
};

Затем используется в клиентском коде как таковой;

local_ptr< PK_MessageAccumulator>::ptr managed = //...

Синтаксис более неуклюж, чем хотелось бы, но это необходимо для поддержки C++03.

Во всех случаях долгосрочное решение состоит в том, чтобы исключить использование auto_ptr или отключить устаревшие предупреждения.

person Niall    schedule 27.07.2015
comment
Спасибо, Ниали. Это очень похоже на Typedef класса шаблона без указания параметров шаблона. По какой-то причине я думал, что в C++ 11 есть более элегантное решение. - person jww; 27.07.2015
comment
В C++11 есть псевдонимы шаблонов, но они не компилируются в C++03 template <class T> using ptr = std::unique_ptr<T>;. В общем, код, который должен быть совместим с C++03, возвращается к коду старого стиля - не обязательно плохому, просто такому, какой он есть. - person Niall; 27.07.2015
comment
Это требует внесения изменений в код везде, где использовался std::auto_ptr. Я не думаю, что это необходимо, см. мой ответ ниже. - person Walter; 27.07.2015

Я попытался добавить:

using auto_ptr = std::unique_ptr;
using std::auto_ptr;
auto_ptr<PK_MessageAccumulator> m(NewSignatureAccumulator(rng));

Но это привело к следующему, даже с включенным.

cryptlib.cpp:770:27: error: no type named 'unique_ptr' in namespace 'std'

Это потому, что std::unique_ptr — это template, а не тип. Вместо этого это должно работать

#if __cplusplus >= 201103L
  // with C++11 we have std::unique_ptr (and std::auto_ptr is deprecated)
  template<typename T>
  using auto_ptr = std::unique_ptr<T>;
#else
  // assuming C++03 when there is std::auto_ptr
  using std::auto_ptr;
#endif

(требуется, чтобы вы использовали в своем коде просто auto_ptr, а не std::auto_ptr).


Конечно, я предполагаю, что вы используете допустимый компилятор C++ и стандартную библиотеку. В Mac OS вы можете использовать (вам может потребоваться установить Xcode и инструменты командной строки)

/usr/bin/c++ -std=c++11 -stdlib=libc++

который вызывает компилятор clang C++ и стандартную библиотеку clang C++.

person Walter    schedule 27.07.2015
comment
Чувак, я мог бы закричать... using auto_ptr = std::unique_ptr<T>; не работает на Apple, потому что находится в пространстве имен std::tr1.... - person jww; 27.07.2015
comment
Моя сага о C++03/C++11 продолжается... Как защитить TR1 на платформах Apple как для C++03, так и для C+ +11?. Если бы я мог проверить это, я бы переместил принятый ответ ... Ебаная Apple и их барахло ... - person jww; 27.07.2015
comment
Я не уверен, что это такое, но ни auto_ptr, ни unique_ptr никогда не были в std::tr1 на инструментах Apple. - person Howard Hinnant; 27.07.2015
comment
@jww Не могли бы вы привести минимальный воспроизводимый (в MAC OS X) пример кода, чтобы мы могли лучше понять вашу проблему? Или, наоборот, лучше объясните проблему. - person Walter; 27.07.2015
comment
Ошибка с using auto_ptr = std::unique_ptr<T>; не имеет ничего общего с TR1. Это потому, что вы используете древнюю libstdc++ в Mac OS X, которая не предоставляет unique_ptr. Простая фраза -std=c++11 не означает, что libstdС++ 2007 года волшебным образом поддерживает новые функции, добавленные после 2007 года. - person Jonathan Wakely; 27.07.2015
comment
Вот где была большая часть проблемы, и почему мои провода так пересеклись: -std=c++11 волшебным образом libstdc++ из 2007 года не поддерживает новые функции, добавленные после 2007 года. Компилятор должен выдали ошибку. Не лгите мне об этом... Я не могу сказать вам, сколько часов я потратил на это, потому что думал, что проблема во мне (как обычно и бывает). - person jww; 28.07.2015

У вас есть два варианта.

  • Используйте auto_ptr в своем приложении и оставьте библиотеку как есть. Предупреждения об устаревании не помешают корректной работе приложения, они только помогают.

  • Используйте unique_ptr в своем приложении и измените библиотеку, чтобы она также использовала unique_ptr.

Вы не можете смешивать их. Если вы не можете изменить библиотеку, вам придется использовать auto_ptr в своем коде.

person Dietrich Epp    schedule 27.07.2015
comment
Спасибо Дитрих. Я контролирую библиотеку и приложение. Когда действует C++11, я хочу использовать unique_ptr. Когда действует C++03, я хочу использовать auto_ptr. (Я не уверен, что вы уловили этот вариант использования выше). - person jww; 27.07.2015
comment
Итак, для ясности, вы говорите, что хотите создать библиотеку, в которой она использует unique_ptr везде с C++11, но auto_ptr с C++03? Потому что вы не можете использовать auto_ptr в библиотеке, но unique_ptr в приложении, которое его использует. - person Dietrich Epp; 27.07.2015
comment
@jww Лучше отключить предупреждение. Даже если вам удалось заставить шаблон псевдонима работать, какой смысл иметь код, который потенциально ведет себя по-разному в C++03 и C++11? - person juanchopanza; 27.07.2015