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
から?
コメント
回答
ほとんどの点で、 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本当に必要なのは、実装を"スワップ"することだけです
コメント
- 非常に良い答えです。私は実際にそれを少し研究しました、そしてあなたは私が試したテストの少なくとも3つに当たりました。 (不足しているのはOSXとClang固有のものです。OSXはまだC ++ 03のTR1名前空間を使用しているため、クマです。次のメソッドを使用して含める必要があります:名前空間' std ividに' unique_ptr 'という名前のタイプはありません= “3e89994714″>
LLVM / Clangでコンパイルする場合)。
tr1
名前空間以外の++ 03/11ミックスはもう存在しません(私はlibc ++を使用し、libstdc ++は使用しません)。tr1が非規範的であったことは知っていますが、' ドラフト(ここ)のどこにも、ファイルは<tr1/...>
である必要がありました。実際、ヘッダー<memory>
などのファイルは名前空間。CXX=...
を指定する(または指定しない)場合、暗黙的に選択を行います。)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
トレードオフ:
-
新しい言語バージョン(別名C ++ 11以降)の場合、エイリアスタイプは正しいスマートポインターにマップされます。 std :: auto_ptrに固有のAPIに実際に依存するユーザーコードは、コンパイラによってフラグが付けられます。これは、実際に修正されることを最終的に保証するものです。
-
レガシーc ++ 03モードでは、型エイリアスはマクロです。これは大まかなものですが、結果の構文
MyPtr<T>
は、コードの残りの部分全体でC ++ 11の場合と同じになります。 -
これを設定するには、すべてのauto_ptr変数を見つけて
MyPtr
に変更する必要があります。
コメント
- 'これが何を参照しているのかが非常に不明確です(言い換えると、 '質問ではありません。
- @autophage答えだと思います…おそらく質問ではありません。
auto_ptr
のスコープ(つまりstd::auto_ptr
)はありますか?スマートポインターは他の名前空間から取得する必要がありますか?Foo::Initialize
をFoo::Foo
に折りたたむこともできます。