I'd like to verify my understanding of how std::thread
makes a copy of a shared_ptr
when it is passed one as an argument.
Assume the following code (C++ 17):
#include <iostream>
#include <memory>
#include <thread>
void const_reference(const std::shared_ptr<int>& data_ptr)
{
std::cout << "value: " << *data_ptr << std::endl;
std::cout << "shared_ptr address: " << &data_ptr << std::endl;
std::cout << "data address: " << data_ptr.get() << std::endl;
std::cout << "Use count: " << data_ptr.use_count() << std::endl;
}
int main()
{
std::shared_ptr<int> data_ptr = std::make_shared<int>(42);
const_reference(data_ptr); // Use count stays 1 as expected - no copy is made.
/*
* value: 42
* shared_ptr address: 0x7ff7ba1b9418
* data address: 0x6000031a91b8
* Use count: 1
*/
std::thread worker {const_reference, data_ptr}; // Use count is 2 - a copy is made.
/*
* value: 42
* shared_ptr address: 0x6000031a91d0
* data address: 0x6000031a91b8
* Use count: 2
*/
worker.join();
return 0;
}
According to cppreference the constructor is as follows:
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );
// The new thread of execution starts executing
INVOKE(decay-copy(std::forward<Function>(f)),
decay-copy(std::forward<Args>(args))...).
If I understand correctly, a copy of the args is already made (using decay-copy
) before it is passed to f
, so the x
in const_reference(x)
is a copy of the shared_ptr
(and of course that can be then taken as a const&
). Is this correct? I'd very much appreciate it if someone with a deep understanding could write clear explanation.
A side note: clang-tidy recommends taking a const reference to a shared_ptr
if it is only used as a const reference, but I'd argue that it is clearer to make it explicit a copy is made when it is used in this way.