web-dev-qa-db-ja.com

std :: shared_ptrでstd :: moveを使用する

次のように定義された関数があります。

void foo(std::shared_ptr<X> x) { ... };

Xに共有ptrを宣言した場合:

std::shared_ptr<X> sourcePtr(new X(...));

次に、次のようにfooを呼び出します。

foo(std::move(sourcePtr));

または

foo(sourcePtr);

最初のオプションを使用すると、sourcePtrがヌルになることを理解しています。また、参照カウントが増加するのを防ぎますか?

それが問題にならない場合、どのオプションを優先すべきですか?そのような決定をするとき、私は他に何かを考慮すべきですか?

27
ksl

はい、共有ポインターを関数に移動すると、次のようになります。

  1. 元のsourcePtrはnullになり、

  2. 参照カウントは変更されません。

関数呼び出し後にsourcePtrの値が不要になることがわかっている場合、それを関数に移動すると、atomic増分(およびその後の減分)が保存されるため、わずかに最適化されます。 sourcePtrが範囲外になるとき)。

ただし、識別子sourcePtrは、nullポインタを保持しているだけで、スコープの残りの部分で引き続き有効であることに注意してください。つまり、移動後にコンパイラを使用しても文句は言われませんが、移動元を忘れると、おそらくnullを逆参照することになります。私はこの「最適化」moveを頻繁に使用する傾向があり、何度か噛まれました。機能に追加の機能が追加され、moveを元に戻すのを忘れた場合、ニースクラッシュが発生します。

したがって、不要になった場合の移動は、わずかな最適化とわずかなメンテナンスの負担です。あなたの場合、どちらがより重要かを判断するのはあなた次第です。

上記は、宣言とsourcePtrの最後の呼び出しの間に実際にfooを使用するコードがあることを前提としています(@WhozCraigに感謝します)。ない場合は、much呼び出しサイトでポインタを作成する方が良いでしょう:

foo(std::make_shared<X>(...));

このようにして、同じ量のアトミック操作を保存します。and潜在的に危険な空の共有ポインターが存在しません。

37
Angew