スマートポインタガイドライン

https://www.chromium.org/developers/smart-pointer-guidelines

スマートポインタガイドライン

スマートポインタとはなにか?

スマートポインタは「スコープオブジェクト」である。普通のポインタと似ているがスコープから外れるとオブジェクトが開放される。C++はガーベッジコレクション言語ではないので、このような機能は重要である。オブジェクトの生涯を自動で管理するこのようなスコープオブジェクトの使用パターンはRAIIと呼ばれる。Resource Acquisition Is Initialization(リソース獲得は初期化時である)。

std::unique_ptr<>の例、これは最も一般的なスマートポインタである:

// We can put a pointer into a std::unique_ptr<> at construction time...
std::unique_ptr value(base::JSONReader::Read(data));
std::unique_ptr foo_ptr(new Foo(...));

// ...or by using reset().
std::unique_ptr bar_ptr;      // Like "Bar* bar_ptr = nullptr;".
bar_ptr.reset(new Bar(...));  // Now |bar_ptr| is non-nullptr and owns the object.

// We can test the std::unique_ptr<> directly.
if (!value)
return false;

// get() accesses the raw pointer underneath.
Foo* raw_ptr = foo_ptr.get();

// We can call through the std::unique_ptr<> as if it were a raw pointer.
DictionaryValue* dict;
if (!value->GetAsDictionary(&dict))
return false;

なぜこれらを使うのか?

スマートポインタはオブジェクトが適切にデストラクトされることを保証する。これにより関数はシンプルで安全になる。これらはある時点で1つのオブジェクト(unique_ptr)が他の1つのオブジェクトを所有していることを強制する。このことによりリークは2重デストラクトを防止する。最後に所有状態の明確化により関数コールでのその移転を期待できる。

どんな種類のスマートポインタが存在するのか?

Chromiumでよく使う2つのポインタはstd::unique_ptr<>scoped_ptr<>である。前者は1人に所有されるオブジェクトであり、後者は参照カウントを用いたオブジェクトである(が通常は使用を避けるべき、下記参照)。C++11に詳しければscoped_ptr<>std::shared_ptr<>と同類である。

base/memory/には興味を引くいくつかの他のオブジェクトがある。

  • WeakPtr<>は実際にはスマートポインタではない。ポインタタイプのように機能するが、自動的に開放すると言うよりも、他のどこかで所有されているオブジェクトを追跡するために使われる。オブジェクトがデストラクトされたとき、Weak_Ptr<>は自動的にnullにセットされ、すでに存在していないことがわかる。(参照解除するときはnullではないかどうかをテストする必要がある。そうしないとnullを参照解除してしまうのと同じことになる。)これはだいたいC++11のstd::weak_ptr<>と同じであるがAPIが異なり、制限も少ない。

これらのスマートポインタをどんなときに使うか?

  • 1人に所有されるオブジェクト - std::unique_ptr<>を使う。これらは参照カウントされていないヒープに作成するオブジェクトに使う。
  • 所有していないオブジェクト - 生ポインタを使うかWeak_Ptr<>を使う。Weak_Ptr<>の参照解除は作成したスレッド(通常'''WeakPtrFactory<>による)と同じスレッドで行わなければならない。オブジェクトがデストロイされる直前とか直後に何かをしたいなら、代わりにコールバックや通知を使ったほうが良い。
  • 参照カウントオブジェクト - scoped_refptr<>を使う。がデザインを見直したほうが良い。参照カウントは所有状態やデストラクト順序を理解するのが難しい(特にスレッドが絡んだとき)。殆どの場合他の方法がある。マルチスレッドで参照カウントを避けることはクラスを1つのスレッドで動作させれば容易である。PostTask()やこれと似たようなプロキシコールをつかって正しいスレッドで動作させる。base::Bind()WeakPtr_<>や他の似たような道具を使うことにより、削除されたオブジェクトでは呼び出しをキャンセルすることができる。現状のコードでは参照カウントを多用しているが、だからといってそれが正しいやり方とは限らないことに注意すること。(そのようなコードを直したらボーナスポイント)。
  • プラットフォーム固有のタイプ - 多くのタイプが有る。base::win::ScopedHandlebase::win::ScopedComptrbase::mac::ScopedCFTypeRefなど。これらはstd::unique_ptr<>とは若干使い勝手が違うことがある。例えば.recieve()によりパラメータ経由でアサインされる。

<途中>

Page last modified on October 05, 2019, at 10:19 AM
Powered by PmWiki