1
votes

When I read the document in cppreference here https://en.cppreference.com/w/cpp/memory/shared_ptr#Example

I am wondering what the possible value of the first lp.use_count() printed out is? I marked it with "<<<<<" in output content.

#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>
 
struct Base
{
    Base() { std::cout << "  Base::Base()\n"; }
    // Note: non-virtual destructor is OK here
    ~Base() { std::cout << "  Base::~Base()\n"; }
};
 
struct Derived: public Base
{
    Derived() { std::cout << "  Derived::Derived()\n"; }
    ~Derived() { std::cout << "  Derived::~Derived()\n"; }
};
 
void thr(std::shared_ptr<Base> p)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::shared_ptr<Base> lp = p; // thread-safe, even though the
                                  // shared use_count is incremented
    {
        static std::mutex io_mutex;
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << "local pointer in a thread:\n"
                  << "  lp.get() = " << lp.get()
                  << ", lp.use_count() = " << lp.use_count() << '\n';
    }
}
 
int main()
{
    std::shared_ptr<Base> p = std::make_shared<Derived>();
 
    std::cout << "Created a shared Derived (as a pointer to Base)\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    std::thread t1(thr, p), t2(thr, p), t3(thr, p);
    p.reset(); // release ownership from main
    std::cout << "Shared ownership between 3 threads and released\n"
              << "ownership from main:\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    t1.join(); t2.join(); t3.join();
    std::cout << "All threads completed, the last one deleted Derived\n";
}

Possible output:

Base::Base()
  Derived::Derived()
Created a shared Derived (as a pointer to Base)
  p.get() = 0x2299b30, p.use_count() = 1
Shared ownership between 3 threads and released
ownership from main:
  p.get() = 0, p.use_count() = 0
local pointer in a thread:
  lp.get() = 0x2299b30, lp.use_count() = 5   <<<<<<<< HERE <<<<<<
local pointer in a thread:
  lp.get() = 0x2299b30, lp.use_count() = 3
local pointer in a thread:
  lp.get() = 0x2299b30, lp.use_count() = 2
  Derived::~Derived()
  Base::~Base()
All threads completed, the last one deleted Derived

@user2452809 's answer is very appreciated, which pointed out an important feature of use_count().

Supposing use_count() would return an accurate count, what would be the answer?

2

2 Answers

2
votes

I wouldn't rely on that value anyway.

In multithreaded environment, the value returned by use_count is approximate (typical implementations use a memory_order_relaxed load)

Check the reference for more information: https://en.cppreference.com/w/cpp/memory/shared_ptr/use_count

0
votes

I think it could be one value of {4,5,6}. Am I right?

Q: Why larger than 3?

A: When printing, at least one thr function is invoked. Including the reference in main function. the use_count should be 3. But it's not possible when one thread sleep for one second and other two hadnot been constructed. On the other hand, if there're two threads finished, the last thread would have a use_count 3. But it would not be the first line because of the thread mutex in printing scope.

Q: Why less than 7?

A: Because during the sleep in subthread, the main thread will run p.reset(). One second is a quite long time to CPU.