web-dev-qa-db-ja.com

C ++ 11でのauto_ptr非推奨の設計変更の処理方法

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の両方をサポートしているため、auto_ptrをヤンキングするのは簡単ではありません。また、ライブラリには外部依存関係がないことに言及する価値もあります。 C++ 03を使用します。 Autotools、Cmake、Boostなどは使用しません...

C++ 03との互換性を維持しながら、C++ 11のauto_ptrから離れるように設計変更をどのように処理する必要がありますか?

12
user118658

ほとんどの点で、 std::unique_ptrstd::auto_ptr の代わりにドロップイン(ただしより安全)されています。 )unique_ptrまたはauto_ptrのどちらかを使用するようにコードに指示する以外に、必要なコード変更が必要です。

これを行うにはいくつかの方法があります(それぞれ独自のリストトレードオフが付属しています)。提供されたコードサンプルを考えると、最初の2つのオプションのどちらかを優先します。

オプション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

トレードオフ;

  • 仮想ベース(特にw.r.t.非仮想デストラクタ)が期待される場所で、継承されたクラスを使用しないでください。これはケースで問題になるはずではありませんが、注意してください
  • もう一度、コードの変更
  • 潜在的な名前空間の不一致-それはすべて、ポインタクラスがどのように使用されるかに依存します

オプション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(); }
};

トレードオフ;

  • 本当に極端なのは、実装を「スワップ」するだけの少し極端な場合
13
Niall

オプション5:直接エイリアス。

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

トレードオフ:

  1. 新しい言語バージョン、別名C++ 11以降では、エイリアスタイプは正しいスマートポインターにマップされます。 std :: auto_ptrに固有のAPIに実際に依存するユーザーコードは、コンパイラによってフラグが付けられます。これは、実際に修正されることを最終的に保証するものです。

  2. レガシーc ++ 03モードでは、タイプエイリアスはマクロです。これは全体ですが、結果の構文MyPtr<T>は、残りのコード全体でC++ 11の場合と同じです。

  3. これを設定するには、すべてのauto_ptr変数を見つけてMyPtrに変更する必要があります。

0
user3726672