web-dev-qa-db-ja.com

gsl :: not_null <T *> vs. std :: reference_wrapper <T> vs. T&

C++コアガイドライン が最近発表されました(おめでとうございます!)gsl::not_nullタイプが心配です。 I.12で述べたように、not_null としてnullであってはならないポインターを宣言します。

Nullptrエラーの逆参照を回避するため。 nullptrの冗長チェックを回避することにより、パフォーマンスを改善します。

...

ソースで意図を述べることにより、実装者とツールは、静的分析を通じていくつかのクラスのエラーを見つけるなどのより良い診断を提供し、ブランチやnullテストの削除などの最適化を実行できます。

意図は明確です。ただし、そのための言語機能は既にあります。 nullにできないポインターは参照と呼ばれます。また、参照は一度作成されるとリバウンドできませんが、この問題はstd::reference_wrapperによって解決されます。

gsl::not_nullstd::reference_wrapperの主な違いは、後者はポインターの代わりにしか使用できないのに対し、前者はnullptr- assignable( F.17:not_nullを使用して、「null」が有効な値ではないことを示します ):

not_nullは、組み込みのポインター専用ではありません。 array_viewstring_viewunique_ptrshared_ptr、およびその他のポインターのようなタイプで機能します。

次のような機能比較表を想像します。

T&

  • nullptrを保存できませんか? -はい
  • 再バインド可能? -いいえ
  • ポインター以外のものの代わりに使用できますか? -いいえ

std::reference_wrapper<T>

  • nullptrを保存できませんか? -はい
  • 再バインド可能? -はい
  • ポインター以外のものの代わりに使用できますか? -いいえ

gsl::not_null<T*>

  • nullptrを保存できませんか? -はい
  • 再バインド可能? -はい
  • ポインター以外のものの代わりに使用できますか? -はい

最後に質問です。

  1. これらの概念の違いについての私の理解は正しいですか?
  2. それはstd::reference_wrapperが今では役に立たないということですか?

[〜#〜] ps [〜#〜]このためにcpp-core-guidelinesおよびguideline-support-libraryというタグを作成しました。

45
Mikhail

参照はnot nullにできないポインターです。参照は意味的にポインタとは大きく異なります。

参照には、割り当てと比較のセマンティクスがあります。つまり、参照を含む割り当てまたは比較操作は、参照されたvalueの読み取りと書き込みを行います。ポインターには(逆に)参照割り当てと比較のセマンティクスがあります。つまり、ポインターを含む割り当てまたは比較操作では、reference自体(つまり、参照されるオブジェクトのアドレス)の読み取りと書き込みを行います。

ご指摘のとおり、参照は(値の割り当てのセマンティクスにより)リバウンドできませんが、reference_wrapper<T>クラステンプレートcanリバウンド。これはreference割り当てセマンティクスを持つためです。それの訳は reference_wrapper<T>は、STLコンテナおよびアルゴリズムで使用するように設計されており、コピー割り当て演算子がコピーコンストラクターと同じことを行わなかった場合、正しく動作しません。しかしながら、 reference_wrapper<T>はまだ値を持っています比較参照のようなセマンティクスなので、STLコンテナーとアルゴリズムで使用される場合、ポインターとは非常に異なる動作をします。例えば、 set<T*>には、同じ値を持つ異なるオブジェクトへのポインタを含めることができますが、set<reference_wrapper<T>>には、特定の値を持つ1つのオブジェクトのみへの参照を含めることができます。

not_null<T*>クラステンプレートには、参照割り当てがありますandポインタのような比較セマンティクス。これはポインターのような型です。これは、STLコンテナーおよびアルゴリズムで使用される場合、ポインターのように動作することを意味します。 nullにすることはできません。

そのため、比較のセマンティクスを忘れた場合を除き、評価は正しいです。いいえ、reference_wrapper<T>は、参照のような値比較のセマンティクスを持っているため、どのようなポインターのような型によっても廃止されません。

28
Joseph Thomson

std::reference_wrapperでカバーされていないgsl::not_nullのユースケースはまだあると思います。基本的に、std::reference_wrapperは参照をミラーリングしてoperator T&変換を行い、not_nulloperator->とのポインターインターフェースを持ちます。すぐに頭に浮かぶユースケースの1つは、スレッドを作成する場合です。

void funcWithReference(int& x) { x = 42; }
int i=0;
auto t = std::thread( funcWithReference, std::ref(i) );

funcWithReferenceを制御できない場合、not_nullを使用できません。

同じことがアルゴリズムのファンクターにも当てはまり、boost::signalsのバインドにも使用しなければなりませんでした。

10
Jens