To understand this problem let's first consider what would be the result of calling std::make_shared<class_type>(),
It returns temporary object which means Xvalue an eXpiring value whose resources can be reused. Now let's see both cases,
some_vector.push_back(make_shared<ClassName>());
std::vector have two overload of push_back and one of them accept rvalue reference that is
constexpr void push_back( T&& value );
It means value is moved into new element, but how? rvalue overload of push_back will move construct new value by invoking shared_ptr( shared_ptr&& r ) noexcept; and ownership of r will be taken and r become empty.
some_vector.emplace_back(make_shared<ClassName>());
In emplace_back( Args&&... args ) element is constructed through std::allocator_traits::construct by perfect forwarding args.. through std::forward<Args>(args)..., It means rvalue will perfect forward and cause same move constructor shared_ptr( shared_ptr&& r ) noexcept; to be invoked.
Conclusion is, both push_back and emplace_back have same effect.
But what is explained above doesn't happen because compiler comes into the picture and what it does, it perform optimization, It means rather than creating temporary objects and moving them into other objects, it directly creates objects in place.
Again result is same in both cases.
Below, supporting code for compiler optimization theory is included and as you can see output only prints one constructor call.
#include <iostream>
using std::cout;
using std::endl;
class Object{
public:
explicit Object(int );
Object(const Object& );
Object(Object&& );
};
Object::Object(int ){
cout<< __PRETTY_FUNCTION__<< endl;
}
Object::Object(const Object& ){
cout<< __PRETTY_FUNCTION__<< endl;
}
Object::Object(Object&& ){
cout<< __PRETTY_FUNCTION__<< endl;
}
int main(){
[[maybe_unused]] Object obj(Object(1));
}
Output:
Object::Object(int)