2019-09-11追記:C++2a(C++20)では P0619R4 が採択され、shared_ptr<T>::unique()メンバ関数は削除(remove)される。


  • shared_ptr参照カウントを利用したスレッド間同期は行わないこと。データ競合(data race)のリスクがある。
  • shared_ptr<T>::uniqueメンバ関数を利用しないこと。C++1zから非推奨(deprecated)。
  • shared_ptr<T>::use_countメンバ関数は、デバッグ用途にのみ利用する。マルチスレッド処理においては信頼できない値を返す可能性がある。



long use_count() const noexcept;
7 Returns: the number of shared_ptr objects, *this included, that share ownership with *this, or 0 when *this is empty.
8 [Note: use_count() is not necessarily efficient. -- end note]

bool unique() const noexcept;
9 Returns: use_count() == 1.
10 [Note: unique() may be faster than use_count(). If you are using unique() to implement copy on write, do not rely on a specific value when get() == 0. -- end note]


shared_ptr and weak_ptr have Notes that their use_count() might be inefficient. This is an attempt to acknowledge reflinked implementations (which can be used by Loki smart pointers, for example). However, there aren't any shared_ptr implementations that use reflinking, especially after C++11 recognized the existence of multithreading. Everyone uses atomic refcounts, so use_count() is just an atomic load.


既存のC++標準ライブラリ実装がすべて参照カウント方式を採用しており、use_countメンバ関数はメモリバリア効果を持たない relaxed load 操作により実装されている。LWG2776より一部引用(下線部は強調)。

The removal of the "debug only" restriction for use_count() and unique() in shared_ptr by LWG 2434 introduced a bug. In order for unique() to produce a useful and reliable value, it needs a synchronize clause to ensure that prior accesses through another reference are visible to the successful caller of unique(). Many current implementations use a relaxed load, and do not provide this guarantee, since it's not stated in the standard. For debug/hint usage that was OK. Without it the specification is unclear and probably misleading.


Synchronization: None.
[Note: get() == nullptr does not imply a specific return value of use_count(). -- end note]
[Note: weak_ptr<T>::lock() can affect the return value of use_count(). -- end note]
[Note: When multiple threads can affect the return value of use_count(), the result should be treated as approximate. In particular, use_count() == 1 does not imply that accesses through a previously destroyed shared_ptr have in any sense completed. -- end note]

下記のようにshared_ptr参照カウンタをスレッド間同期に使うコードは、データ競合(data race)による未定義動作(undefined behavior)を引き起こす。

int main() {
  int result = 0;
  auto sp1 = std::make_shared<int>(0);  // refcount: 1

  // Start another thread
  std::thread another_thread([&result, sp2 = sp1]{  // refcount: 1 -> 2
    result = 42;  // [W] store to result
    // [D] expire sp2 scope, and refcount: 2 -> 1

  // Do multithreading stuff:
  //   Other threads may concurrently increment/decrement refcounf.

  if (sp1.unique()) {      // [U] refcount == 1?
    assert(result == 42);  // [R] read from result
    // This [R] read action cause data race w.r.t [W] write action.

  // Side note: thread termination and join() member function
  // have happens-before relationship, so [W] happens-before [R]
  // and there is no data race on following read action.
  assert(result == 42);


*1:2016年12月現在の(PDF)N4618 Working Draftからはuniqueメンバ関数が削除され、D.13 Deprecated shared_ptr observersに移動している。

*2:同一オブジェクトを参照する shared_ptr オブジェクト間をリンクリストで相互参照しあう方式。use_count メンバ関数ではリンクリストを辿って shared_ptr オブジェクト数を数える必要があるが、shared_ptr オブジェクトが唯一、つまりリンクリストが1ノードの判定は効率的に行える。