This example does not even compile:
void Function(std::shared_ptr<Good> p) { std::cout << p.use_count() << '\n'; } int main() { Good* p = new Good; std::shared_ptr<Good> p1(p); Function(p);
shared_ptr
has an explicit
constructor to stop this.
To complete this compilation you need to write:
Function( std::shared_ptr<Good>(p) );
which is obviously wrong, and if someone is going to make this mistake, they are just as likely:
Function( CResource(std::shared_ptr<Good>(p)) );
So why did you bother to write CResource
? What does he add?
To deploy on Konrad Rudolph an excellent answer:
The answer to your question on how to avoid problems is to follow RAII and complete it completely.
We will ignore the example, which does not even compile, and do not look at it above:
Good* p = new Good; std::shared_ptr<Good> gp3(p); std::shared_ptr<Good> gp4(p);
This code cannot follow the RAII idiom. You get the resource:
Good* p = new Good;
But do not initialize the type of RAII. Bad .
Then you initialize the object using some existing resource:
std::shared_ptr<Good> gp3(p);
This is also a bad . You must initialize the RAII type at the same time as acquiring the resource, and not separately (not even separated by just one line).
Then you repeat the same error:
std::shared_ptr<Good> gp4(p);
You marked this line as "BAD", but in fact the previous two lines were just as bad. The third line will cause undefined behavior, but the first two lines allowed this error to penetrate when it was supposed to get complicated. If you never had a Good*
suspension, then you could not use it to initialize gp4
, you would need to say shared_ptr<Good> gp4(gp3.get())
, which is clearly wrong, no one will do that.
The rule is pretty simple: don't use a raw pointer and put it in shared_ptr
. A raw pointer that you did not allocate is not a collection of resources, so do not use it to initialize. The same thing happens inside Function
, it should not take a raw pointer and use it to initialize shared_ptr
, which becomes the property of the type.
This is C ++, therefore it is impossible to protect against all the wrong ways of writing code, you cannot stop sufficiently motivated idiots from shooting in the foot, but all the recommendations and tools exist to prevent this if you follow the recommendations.
You have an interface in which it forces you to transfer ownership by passing a raw pointer, try replacing the interface so that it uses unique_ptr
to transfer ownership, or if this is completely impossible to do then try wrapping the interface in a more secure version using unique_ptr
to transfer ownership , and only as a last resort use a dangerous interface, but write it down very explicitly to transfer ownership.