Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is raw pointer to shared_ptr construction allowed in all cases?

I was reading Top 10 dumb mistakes to avoid with C++11 smart pointer. Number #5 reads:

Mistake # 5 : Not assigning an object(raw pointer) to a shared_ptr as soon as it is created !

int main()
{
    Aircraft* myAircraft = new Aircraft("F-16"); 
    shared_ptr<aircraft> pAircraft(myAircraft);
    ...
    shared_ptr<aircraft> p2(myAircraft); 
    // will do a double delete and possibly crash
}

and the recommendation is something like:

Use make_shared or new and immediately construct the pointer with it.

Ok, no doubt about it the problem and the recommendation. However I have a question about the design of shared_ptr. This is a very easy mistake to make and the whole "safe" design of shared_ptr could be thrown away by very easy-to-detect missuses.

Now the question is, could this be easily been fixed with an alternative design of shared_ptr in which the only constructor from raw pointer would be that from a r-value reference?

template<class T>
struct shared_ptr{
    shared_ptr(T*&& t){...basically current implementation...}
    shared_ptr(T* t) = delete; // this is to...
    shared_ptr(T* const& t) = delete; // ... illustrate the point.
    shared_ptr(T*& t) = delete;
    ...
};

In this way shared_ptr could be only initialized from the result of new or some factory function.

Is this an underexploitation of the C++ language in the library? or What is the point of having a constructor from raw pointer (l-value) reference if this is going to be most likely a misuse?

Is this a historical accident? (e.g. shared_ptr was proposed before r-value references were introduced, etc) Backwards compatibility?

(Of course one could say std::shared_ptr<type>(std::move(ptr)); that that is easier to catch and also a work around if this is really necessary.)

Am I missing something?

like image 249
alfC Avatar asked May 18 '16 07:05

alfC


2 Answers

Pointers are very easy to copy. Even if you restrict to r-value reference you can sill easily make copies (like when you pass a pointer as a function parameter) which will invalidate the safety setup. Moreover you will run into problems in templates where you can easily have T* const or T*& as a type and you get type mismatches.

So you are proposing to create more restrictions without significant safety gains, which is likely why it was not in the standard to begin with.

The point of make_shared is to atomize the construction of a shared pointer. Say you have f(shared_ptr<int>(new int(5)), throw_some_exception()). The order of parameter invokation is not guaranteed by the standard. The compiler is allowed to create a new int, run throw_some_exception and then construct the shared_ptr which means that you could leak the int (if throw_some_exception actually throws an exception). make_shared just creates the object and the shared pointer inside itself, which doesn't allow the compiler to change the order, so it becomes safe.

like image 156
Sorin Avatar answered Sep 28 '22 22:09

Sorin


I do not have any special insight into the design of shared_ptr, but I think the most likely explanation is that the timelines involved made this impossible:

The shared_ptr was introduced at the same time as rvalue-references, in C++11. The shared_ptr already had a working reference implementation in boost, so it could be expected to be added to standard libraries relatively quickly.

If the constructor for shared_ptr had only supported construction from rvalue references, it would have been unusable until the compiler had also implemented support for rvalue references.

And at that time, compiler and standards development was much more asynchronous, so it could have taken years until all compiler had implemented support, if at all. (export templates were still fresh on peoples minds in 2011)

Additionally, I assume the standards committee would have felt uncomfortable standardizing an API that did not have a reference implementation, and could not even get one until after the standard was published.

like image 39
Benno Avatar answered Sep 28 '22 21:09

Benno