This might be a stupid question.
Let's say we're in C++11 land and we use make_shared() to create a smart pointer. We then use this smart pointer to initialize a variable with like this:
std::shared_ptr<class> = make_shared(/* args to c'tor of class*/ );
Now I know two things:
shared_ptr
which is returned by make_shared
.Does this mean that on every instance of make_shared a temporary copy of the shared_ptr is created and inserted into the copy constructor? Because this would mean for thread safety that a lock would have to be taken across the initialisation in case other threads preempt the thread and call shared_ptr::use_count() member function?
There are two things to avoid the copy:
for code auto foo = std::make_shared<Foo>();
RVO will create the object directly on the stack. and even we disable the RVO by -fno-elide-constructors
, the move constructor will try used as the returned object from make_shared
is a temporary one.
Below is a simple test code. (this code only show the concept but not for a real-world shared_ptr implementation)
#include <iostream>
template <typename T>
struct my_shared_ptr
{
T *t_{nullptr};
my_shared_ptr(T *t): t_(t) {
std::cout << "constructor" << std::endl;
};
my_shared_ptr(const my_shared_ptr<T>&) {
std::cout << "copy" << std::endl;
}
my_shared_ptr<T>& operator=(const my_shared_ptr<T>&) {
std::cout << "copy" << std::endl;
return *this;
}
#ifndef NO_MOVE
my_shared_ptr(my_shared_ptr<T>&&) {
std::cout << "move" << std::endl;
}
my_shared_ptr<T>& operator=(my_shared_ptr<T>&&) {
std::cout << "move" << std::endl;
return *this;
}
#endif
};
template <typename T>
my_shared_ptr<T>
my_make_shared() {
return my_shared_ptr<T>(new T);
}
struct Foo {};
int main()
{
auto foo = my_make_shared<Foo>();
return 0;
}
Condition 1, compile with c++11 shows:
$ g++ a.cc -std=c++11 ; ./a.out
constructor
Condition 2, compile with c++11/disable RVO shows:
$ g++ a.cc -std=c++11 -fno-elide-constructors ; ./a.out
constructor
move
move
Condition 3, compile with c++11/disable RVO/no move shows:
$ g++ a.cc -std=c++11 -fno-elide-constructors -DNO_MOVE ; ./a.out
constructor
copy
copy