標準ライブラリのダングリングリンクを制御する方法がないのはなぜですか?

C ++標準ライブラリにスマートポインターが登場した後、オブジェクトの有効期間を制御する問題は解決されました。 スタック上にオブジェクトを作成できます。スコープを終了すると、オブジェクトは自動的に削除されます。unique_ptrを使用して排他的所有権を持つオブジェクトを作成するか、共有所有権を持つshared_ptrを作成します。 ただし、標準ライブラリのshared_ptrに対してのみ、無効なポインタの使用を防ぐ非所有のweak_ptrポインタがあります。 その他の場合は、「古い危険な」生のポインターを使用します。



言語開発者はこの問題をどのように解決することを提案しますか?



CppCoreGuidelines Webサイトには、いくつかの興味深いドキュメントがあります( ここここ )。

主なメッセージは次のとおりです。ゼロオーバーヘッドの原則に違反しない限り、安全な非所有ポインタを実装することはできません。 したがって、このようなツールをランタイムに実装するのではなく、静的コード分析により問題の解決を試みます。



私はこの立場に同意しません、そして、ここに私の議論があります:



  1. 静的分析では、すべての問題を把握できるわけではありません。 記事の著者自身は、一部の構成を安全とマークすることが必要になる場合があり、コードの正確性の問題は開発者の良心に任せていると述べています。
  2. 静的解析が機能するためには、コンパイラのサポートが必要です。 表示される場合-不明です。
  3. 静的分析では、弱い非所有ポインターを使用できません(オブジェクトが削除されると消えるweak_ptrに似ています)。
  4. そのようなポインターを実装すると、オーバーヘッドがゼロの原則に違反します-それは本当です。 しかし、私の意見では、shared_ptrもこの原則に違反しています。 ref_countオブジェクトが追加されているか、たとえば、小さな文字列が最適化された文字列があります。 いずれにせよ、標準ライブラリは明確に定義された特性を持つクラスを提供し、プログラマーはこれらのクラスが自分に適しているかどうかを決定します。


私の意見では、標準ライブラリはすべての主要なプログラミングシナリオのクラスを提供する必要があります。 非所有ポインターとぶら下がりアクセスは、C ++の大規模でまだ閉じられていないトピックです。 標準ライブラリは、そのようなポインタを持つオプションの機会をプログラマに提供すべきだと思います。



RSLプロジェクトでは、このようなポインターを実装しようとしました。 基本的な考え方は新しいものではありません。破棄時に削除の事実をポインタに通知するオブジェクトが必要です。



したがって、2つのクラスがあります。



  1. rsl :: track :: trackable-削除されたときにポインターを通知するクラス。
  2. rsl ::トラック::ポインター -実際には非所有ポインター。


rsl :: track :: pointerが同じrsl :: track :: trackableオブジェクトを指す場合、それらは二重にリンクされたリストに並んでいます。 リストの先頭へのポインタは、 rsl :: track :: trackableに含まれています。 したがって、ポインターの作成には一定の時間がかかります。 r sl :: track :: trackableのサイズは1つのポインターであり、 rsl :: track ::ポインターは4ポインター(オブジェクトへのポインター、リストを整理するための2つのポインター、および多態的な動作を実装するための別のポインター)です。 おそらく、ポインターのより最適な構成は、誰かが知っているなら教えてください。



また、この実装はスレッドセーフではありません。異なるスレッドでの動作を保証するには、std :: atomic_flagを追加し、ポインターの変更を遅くする必要があります。



さらに、 アロケーター対応コンテナーの出現により、標準コンテナーでrsl :: track ::ポインターを使用できるようにするアロケーターを実装できるようになりました。 主なアイデアは、現在、コンテナ内のすべての割り当てがコンテナに格納されているアロケータのインスタンス、またはそのテンプレートコピーによって行われ、アロケータにrsl :: track :: trackableを格納してコピーに転送できることです。



このテストは、std ::配列やunique_ptrを含む主要な標準コンテナーでの作業例を提供します。



結論として、 rsl :: track ::ポインターが役立つ別のシナリオを示します 。 これらは、 これ削除するのと同様の状況です。 通常、これはオブジェクトの外部でコード、ファンクター、またはシグナルを呼び出すときに間接的に発生します。 この種のエラーはまれですが、認識するのは困難です。

そのような場合(およびダングリングリンクを介したアクセスに関するその他の問題)は、 google sanitizersなどのツールを使用して、このような問題をキャッチできます。



しかし、これらのツールには欠点があります。



  1. すべてのプラットフォームで機能するわけではありません。
  2. コードの実装が必要です-コードは本番とは異なります。
  3. オブジェクトが削除されるとゼロになるポインターであるweak_ptrの類似物はありません。
  4. 無効なポインターによってアクセスの時間と場所を検出します。 原則として、より興味深い瞬間は、ポインターのあるオブジェクトが削除されるときです。 同じ理由で、計装は不適切なアクセスのすべてのケースを検出するのではなく、テスト中に実際に動作したケースのみを検出します。


ライブラリがC ++開発者に役立つことを願っています。 このような問題を解決する方法は他にもあると思いますので、コメントを喜んで聞きます。



PSもう一度、便宜上、 RSLライブラリコードへのリンクを提供します。



All Articles