[解決済み] スマートポインターとは何ですか?
質問
スマートポインターとはどのようなもので、どのような場合に使用するのですか?
どのように解決するのですか?
アップデイト
この回答はかなり古いもので、当時「良かった」もの、つまりBoostライブラリが提供するスマートポインタについて説明しています。C++11以降、標準ライブラリは十分なスマートポインタの型を提供しています。
std::unique_ptr
,
std::shared_ptr
そして
std::weak_ptr
.
もありました。
std::auto_ptr
. これは、スコープ付きポインタに非常によく似ていますが、コピーされるという "特別" 危険な能力も持っており、これは予期せず所有権を移してしまうということを除けば、非常によく似ています。
C++11で非推奨となり、C++17で削除された
ということで、使うべきではありません。
std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership.
// p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.
旧アンサー
スマートポインターは、「生の」(または「裸の」)C++ポインターをラップするクラスで、指されているオブジェクトの寿命を管理するためのものです。スマートポインタの型は1つではありませんが、どれも生のポインタを実用的な方法で抽象化しようとするものです。
スマートポインタは生ポインタよりも優先されるべきです。もしポインターを使う必要があると感じたら、(最初に 本当に なぜなら、スマートポインタを使えば、生ポインタの問題点(主にオブジェクトの削除忘れやメモリリーク)を軽減できるからです。
生ポインタの場合、プログラマはオブジェクトが不要になったときに明示的に破棄しなければなりません。
// Need to create the object to achieve some goal
MyObject* ptr = new MyObject();
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?
それに比べてスマートポインターは、オブジェクトを破棄するときのポリシーを定義しています。オブジェクトを作成する必要はありますが、破棄することを気にする必要はありません。
SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.
// Destruction of the object happens, depending
// on the policy the smart pointer class uses.
// Destruction would happen even if DoSomething()
// raises an exception
最も単純なポリシーは、スマートポインタラッパーオブジェクトのスコープに関わるもので、例えば、以下のように実装されています。
boost::scoped_ptr
または
std::unique_ptr
.
void f()
{
{
std::unique_ptr<MyObject> ptr(new MyObject());
ptr->DoSomethingUseful();
} // ptr goes out of scope --
// the MyObject is automatically destroyed.
// ptr->Oops(); // Compile error: "ptr" not defined
// since it is no longer in scope.
}
なお
std::unique_ptr
インスタンスをコピーすることはできません。これは、ポインタが何度も (不正に) 削除されるのを防ぐためです。しかし、呼び出す他の関数にその参照を渡すことはできます。
std::unique_ptr
は、オブジェクトの寿命を特定のコードブロックに結びつけたい場合や、他のオブジェクトの中にメンバーデータとして埋め込んだ場合、その他のオブジェクトの寿命となる場合に便利です。オブジェクトは、コードのブロックが終了するまで、またはオブジェクトが破壊されるまで存在します。
より複雑なスマートポインタのポリシーとして、ポインタの参照カウントがあります。これはポインターをコピーすることを可能にします。オブジェクトへの最後の "参照" が破棄されると、オブジェクトは削除されます。このポリシーは次のように実装されています。
boost::shared_ptr
と
std::shared_ptr
.
void f()
{
typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
MyObjectPtr p1; // Empty
{
MyObjectPtr p2(new MyObject());
// There is now one "reference" to the created object
p1 = p2; // Copy the pointer.
// There are now two references to the object.
} // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero.
// The object is deleted.
オブジェクトの寿命がもっと複雑で、コードの特定のセクションや他のオブジェクトに直接結びついていない場合、参照カウントされたポインタが非常に便利です。
参照カウント式ポインターの欠点は、ダングリングリファレンスが発生する可能性があることです。
// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!
もう一つの可能性は、循環参照を作ることです。
struct Owner {
std::shared_ptr<Owner> other;
};
std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1
// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!
この問題を回避するために、BoostとC++11の両方が、C++11で定義された
weak_ptr
への弱い(カウントされない)参照を定義するためのものです。
shared_ptr
.
関連
-
[解決済み】エラー:不完全な型へのメンバーアクセス:前方宣言の
-
[解決済み】VC++の致命的なエラーLNK1168:書き込みのためにfilename.exeを開くことができません。
-
[解決済み】c++で.txtファイルから2次元の配列に読み込む
-
[解決済み] using namespace std;」はなぜバッドプラクティスだと言われるのですか?
-
[解決済み] static_cast, dynamic_cast, const_cast, reinterpret_cast はいつ使うべきですか?
-
[解決済み] コピーアンドスワップ慣用句とは?
-
[解決済み] ムーブセマンティクスとは何ですか?
-
[解決済み] なぜ、オブジェクトそのものではなく、ポインタを使用しなければならないのですか?
-
[解決済み] const int*、const int * const、int const *の違いは何ですか?
-
[解決済み】C++11のラムダ式って何?
最新
-
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 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C++ クラスヘッダが含まれているときに「不明な型」があるのはなぜですか?重複
-
[解決済み】C++ - 解放されるポインタが割り当てられていないエラー
-
[解決済み】Cygwin Make bash コマンドが見つかりません。
-
[解決済み] 既に.objで定義されている-二重包含はない
-
[解決済み】C++プログラムでのコンソールの一時停止
-
[解決済み] 解決済み] `pthread_create' への未定義の参照 [重複] [重複
-
[解決済み】 while(cin) と while(cin >> num) の違いは何ですか?)
-
[解決済み】Enterキーを押して続行する
-
[解決済み】演算子のオーバーロード C++; <<操作のパラメータが多すぎる
-
[解決済み】エラー。引数リストに一致するコンストラクタのインスタンスがない