[解決済み] スマートポインタを常に使用するのは良い習慣ですか?
質問
私はスマートポインタは生ポインタよりもずっと快適だと感じています。そこで、以下のようにするのは良いアイデアでしょうか? 常に スマートポインタを使うのが良いのでしょうか?(私はJava出身なので、明示的なメモリ管理の考え方はあまり好きではないことに注意してください。ですから、スマートポインタの性能に深刻な問題がない限り、スマートポインタを使い続けたいと思います。)
注:私はJava出身ですが、スマートポインタの実装とRAIIの概念についてはよく理解しています。ですから、回答を投稿するときは、私の側からこの知識を当然と考えることができます。私はほとんどすべての場所で静的割り当てを使用し、必要な場合にのみポインタを使用します。私の質問は単に 私は常に生のポインタの代わりにスマートポインタを使用することができますか?
どのように解決するのですか?
いくつかの編集を考えると、包括的な要約が有用であるような印象を受けます。
1. しない場合
スマートポインタを使うべきではない状況が2つあります。
1つ目は、スマートポインタを使うべきではない状況と全く同じです。
C++
クラスを実際に使用してはいけません。IE:ソースコードをクライアントに提供しない場合、DLL境界。逸話的に言ってみましょう。
2つ目はもっと頻繁に起こります。 スマート・マネージャーはオーナーシップを意味する . 例えば、既存のリソースの寿命を管理せずに、ポインタを使用して指し示すことがあります。
void notowner(const std::string& name)
{
Class* pointer(0);
if (name == "cat")
pointer = getCat();
else if (name == "dog")
pointer = getDog();
if (pointer) doSomething(*pointer);
}
この例では制約があります。しかし、ポインタは無効な場所(ヌルポインタ)を指すことがあるという点で、参照とは意味的に異なるものです。この場合、オブジェクトのライフタイムを管理したくないので、代わりにスマートポインタを使わなくても全く問題ありません。
2. スマートマネージャ
スマート・マネージャ・クラスを記述していない限り、もしキーワード
delete
を使用すると、何か間違ったことをしていることになります。
これは賛否両論のある視点ですが、多くの欠陥のあるコードの例をレビューした後、私はもうこれ以上チャンスを逃さないようにしています。ですから、もしあなたが
new
と書くなら、新しく割り当てられたメモリのためにスマートなマネージャが必要です。そして、今すぐそれが必要なのです。
だからといって、プログラマーとしての資質が低いというわけではありません! それどころか、車輪を何度も再発明する代わりに、動作が証明されているコードを再利用することは重要なスキルです。
さて、本当に難しいのは、どのようなスマートなマネージャーが必要なのか、ということです。
3. スマートポインタ
世の中には様々なスマートポインタがあり、様々な特徴があります。
スキップ
std::auto_ptr
は一般的に避けるべきものです(そのコピーセマンティックはねじ曲げられます)。
-
scoped_ptr
: オーバーヘッドがなく、コピーや移動ができません。 -
unique_ptr
: オーバーヘッドなし、コピー不可、移動可。 -
shared_ptr
/weak_ptr
: いくつかのオーバーヘッド (参照カウント) がありますが、コピーすることができます。
通常、以下のどちらかを使用するようにしてください。
scoped_ptr
または
unique_ptr
. 複数のオーナーが必要な場合は、デザインを変更してみてください。もしデザインを変更することができず、本当に複数のオーナーが必要な場合は
shared_ptr
を使うことができますが、weak_ptr
を使うべきです。
4. スマートコンテナ
多くのスマートポインタはコピーされることを意図していないため、STLコンテナでの使用は多少危ういです。
に頼るのではなく
shared_ptr
とそのオーバーヘッドに頼らず、スマートコンテナで
ブーストポインタコンテナ
. これらは古典的なSTLコンテナのインタフェースをエミュレートしていますが、自分自身のポインタを格納します。
5. 自分でロールする
独自のスマートマネージャをロールバックしたい場合があります。その際、使用しているライブラリの機能を見逃していないか、事前に確認してください。
例外が発生する状況でスマートマネージャを書くのは非常に難しいです。通常、メモリが利用可能であることを仮定することはできません (
new
が失敗する可能性がある)、あるいは
Copy Constructor
があります。
no throw
を保証します。
を無視しても、多少は許容されるかもしれません。
std::bad_alloc
例外を無視して
Copy Constructor
が失敗しないようにする必要があります...結局のところ、それは
boost::shared_ptr
はそのデレッターのために
D
テンプレート・パラメータに適用されます。
しかし、特に初心者の方にはお勧めしません。厄介な問題で、今すぐにはバグに気づけないでしょうから。
6. 事例紹介
// For the sake of short code, avoid in real code ;)
using namespace boost;
// Example classes
// Yes, clone returns a raw pointer...
// it puts the burden on the caller as for how to wrap it
// It is to obey the `Cloneable` concept as described in
// the Boost Pointer Container library linked above
struct Cloneable
{
virtual ~Cloneable() {}
virtual Cloneable* clone() const = 0;
};
struct Derived: Cloneable
{
virtual Derived* clone() const { new Derived(*this); }
};
void scoped()
{
scoped_ptr<Cloneable> c(new Derived);
} // memory freed here
// illustration of the moved semantics
unique_ptr<Cloneable> unique()
{
return unique_ptr<Cloneable>(new Derived);
}
void shared()
{
shared_ptr<Cloneable> n1(new Derived);
weak_ptr<Cloneable> w = n1;
{
shared_ptr<Cloneable> n2 = n1; // copy
n1.reset();
assert(n1.get() == 0);
assert(n2.get() != 0);
assert(!w.expired() && w.get() != 0);
} // n2 goes out of scope, the memory is released
assert(w.expired()); // no object any longer
}
void container()
{
ptr_vector<Cloneable> vec;
vec.push_back(new Derived);
vec.push_back(new Derived);
vec.push_back(
vec.front().clone() // Interesting semantic, it is dereferenced!
);
} // when vec goes out of scope, it clears up everything ;)
関連
-
[解決済み】C++コンパイルタイムエラー:数値定数の前に期待される識別子
-
[解決済み】Visual Studio 2013および2015でC++コンパイラーエラーC2280「削除された関数を参照しようとした」が発生する
-
[解決済み】c++で.txtファイルから2次元の配列に読み込む
-
[解決済み] using namespace std;」はなぜバッドプラクティスだと言われるのですか?
-
[解決済み] スマートポインターとは何ですか?
-
[解決済み] なぜ、オブジェクトそのものではなく、ポインタを使用しなければならないのですか?
-
[解決済み] 仮想デストラクタはいつ使うのか?
-
[解決済み] C++で配列はどのように使うのですか?
-
[解決済み] ループ内での変数宣言、グッドプラクティスかバッドプラクティスか?
-
[解決済み】高放射能環境下で使用するアプリケーションのコンパイルについて
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】構造体のベクター初期化について
-
[解決済み】コンストラクターでのエラー:識別子を期待されますか?
-
[解決済み】LLVMで暗黙のうちに削除されたコピーコンストラクタの呼び出し
-
[解決済み】クラステンプレートの引数リストがない
-
[解決済み】 != と =! の違いと例(C++の場合)
-
[解決済み】C++エラーです。"配列は中括弧で囲まれたイニシャライザーで初期化する必要がある"
-
[解決済み】テンプレートの引数1が無効です(Code::Blocks Win Vista) - テンプレートは使いません。
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み】演算子のオーバーロード C++; <<操作のパラメータが多すぎる
-
[解決済み】変数やフィールドがvoid宣言されている