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

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

コメント

  • auto_ptrのスコープ(つまりstd::auto_ptr)はありますか?スマートポインターは他の名前空間から取得する必要がありますか?
  • 余談ですが、Foo::InitializeFoo::Fooに折りたたむこともできます。
  • @ MSalters-ええ、それはいつも私が少し不快に感じていたものの1つです。ライブラリは1990年代に設計され、設計はMFCに似ていると考えます。つまり、より低いものでした。レベルC ++の構築、次に"上位レベルの"オブジェクトの構築。この機能はトレードオフとして使用されたため、クラスは' 6つまたは12の異なるコンストラクターがあります。 (この時点で、私が行ったことを実行し、POD型のメンバー変数がC ++コンストラクターで正常なデフォルトに初期化されていることを確認しました。)

回答

ほとんどの点で、 std::unique_ptr がドロップインされました(ただし、より安全です) std::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 

トレードオフ;

  • 仮想ベース(特に非仮想デストラクタ)が期待される継承されたクラスを使用しようとしないでください。これは、ケースの問題-しかし、それに注意してください
  • 繰り返しになりますが、コードが変更されます
  • 名前空間の不一致の可能性-これはすべて、ポインタクラスの使用方法によって異なります

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

トレードオフ;

  • A本当に必要なのは、実装を"スワップ"することだけです

コメント

LLVM / Clangでコンパイルする場合)。

  • @jww。 OS X(XCode6.4およびAppleLLVMバージョン6.1.0(clang-602.0.53)(LLVM 3.6.0svnに基づく))で' mであり、Cに問題はありません。 tr1名前空間以外の++ 03/11ミックスはもう存在しません(私はlibc ++を使用し、libstdc ++は使用しません)。tr1が非規範的であったことは知っていますが、' ドラフト(ここ)のどこにも、ファイルは<tr1/...>である必要がありました。実際、ヘッダー<memory>などのファイルは名前空間。
  • @jww。コンパイラ、ライブラリ、およびターゲットデバイスの特定の組み合わせを考えると、さらにいくつかのハンドスタンドを実行する必要があると思います。それ以外の場合、OS Xでは、clangとlibc ++への移行を検討してください。率直に言って、libc ++はOSXの新しい" native " C ++ライブラリであると考えています。デフォルトではこれを使用します。 clang / Appleの関係の歴史と、OS X上のGCCツールが古くなっている(ライブラリ)か、削除されたばかりである(GCCがとにかくclangの薄いスタブであることがわかっている限り)以外は、これらの主張をサポートする方法はありません。 )。
  • "それ以外の場合、OS Xでは、clangとlibc ++への移行を検討してください… " -ええ、私はあなたに同意します。ただし、ユーザーにその選択をさせ、強制しないようにします。 (CXX=...を指定する(または指定しない)場合、暗黙的に選択を行います。)
  • ここでは'の場合です。これは、OS X 10.7および10.8で非常に多くの問題を引き起こしています:c++ -v -std=c++11 -x c++ - < /dev/null。ダンプされたインクルードディレクトリをgrep'dインクルードしますが、 インクルードunique_ptr
  • 回答

    オプション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に変更する必要があります。

    コメント

    • 'これが何を参照しているのかが非常に不明確です(言い換えると、 '質問ではありません。
    • @autophage答えだと思います…おそらく質問ではありません。

    コメントを残す

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です