22

に参照カウントが格納されていると仮定するとstd::shared_ptr(標準では必要ないことはわかっていますが、必要としない実装については知りません)、その参照カウントのビット数には制限があり、最大数があることを意味します。サポートされている参照。これは、次の 2 つの疑問につながります。

  • この最大値は?
  • それを超えようとするとどうなりますか (たとえば、最大参照カウントを持つオブジェクトを参照する std::shared_ptr をコピーすることによって)? std::shared_ptrコピー コンストラクタが宣言されていることに注意してくださいnoexcept

この規格は、これらの質問のいずれかに光を当てていますか? gcc、MSVC、Boost などの一般的な実装はどうですか?

4

5 に答える 5

20

関数からいくつかの情報を取得できshared_ptr::use_count()ます。§20.7.2.2.5 は言う:

long use_count() const noexcept;

戻り値: と所有権を共有shared_ptrする、含まれるオブジェクトの数、またはが空の場合。*this*this0*this

[注:use_count()必ずしも効率的であるとは限りません。—終了注]

一見すると、long戻り値の型は最初の質問に答えているように見えます。shared_ptrただし、メモは、参照のリストなど、必要な種類の参照カウントを自由に使用できることを暗示しているようです。この場合、理論的には最大参照カウントはありません (実際には確かに制限があります)。

私が見つけた同じオブジェクトへの参照数の制限への参照は他にありません。

use_countスローしないことと(明らかに)カウントを正しく報告することの両方が文書化されていることに注意するのは興味深いことです。実装がlongカウントにメンバーを使用しない限り、これらの両方が常に理論的に保証される方法はわかりません。

于 2012-09-13T08:20:50.910 に答える
7

標準が何を示唆しているかはわかりませんが、実際に見てください。

参照カウントは、おそらくある種のstd::size_t変数です。-1+2^32この変数は、最大32 ビット環境および最大-1+2^6464ビット環境で値を保持できます。

ここで、この変数がこの値に到達するために何が起こるかをイメージしてください。2^32 または 2^64 のshared_ptrインスタンスが必要です。それは沢山。shared_ptr実際、1 つは約 8/16 バイトの大きさであるため、この数に達するずっと前にすべてのメモリが使い果たされるほどの数です。

したがって、refcount 変数のサイズが十分に大きい場合、参照カウントの制限に達する可能性はほとんどありません。

于 2012-09-13T08:24:08.297 に答える
2

place new を使用して共有ポインターをインスタンス化し、それらを削除しないことで、何が起こるかを知ることができます。その後、32 ビットの制限に簡単に到達できます。

于 2012-09-13T21:37:21.517 に答える
0

C++11 標準longでは、オブザーバー関数の戻り値の型として指定されていますが、実装が共有所有権use_count()までサポートする必要があるかどうかは明示的に指定されていません。2^(sizeof(long)*8-1)-1

また、参照カウンターがオーバーフローしたときに何が起こるかも指定されていません。

実装 (例: boost::shared_ptrFedora 23、x86-64 では 1.58) は内部で 32 ビット カウンターを使用し、オーバーフローをチェックしません。

つまり、次のことを意味します。

  1. 最大参照カウントは2^31-1です。
  2. オーバーフローして所有権を解放すると、使用後の解放の問題が発生する可能性があります

ブーストはプラットフォームごとに異なる低レベルの特殊化を使用するため、ブレークポイントを設定することで詳細を確認できます*add_ref_lock。Fedora 23/x86-64 では、ここで停止します。

/usr/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp
[..]
int use_count_;        // #shared
int weak_count_;       // #weak + (#shared != 0)
[..]
bool add_ref_lock() // true on success
{
    return atomic_conditional_increment( &use_count_ ) != 0;
}

以下も参照してください。

GNU STL (libstdc++) の shared_pointer 実装は、Boost 1.32 のものに基づいており、この問題 (Fedora 23/x86-64 で) もあり、_Atomic_word型は参照カウントに使用されます。また、これは 32 ビットのみであり、オーバーフローはチェックされません。

対照的に、LLVM の libc++shared_ptr実装はlong参照カウンターとして使用します。つまり、x86-64 のような LP64 プラットフォームでは、所有者までの間でオブジェクトを共有できます2^63-1

于 2016-09-18T10:27:39.450 に答える