Boost's make_shared()
function promises to be exception-safe while attempting to create a shared_ptr
.
Why is there no make_scoped()
equivalent? Is there a common best practice?
Here's a code example from the boost::scoped_ptr
documentation that seems unsafe to me:
boost::scoped_ptr<Shoe> x(new Shoe);
This line of code will do these three things in order:
Shoe
Shoe
boost::scoped_ptr<Shoe>
If the constructor for Shoe
throws an exception, memory will be leaked. (see R. Martinho Fernandes answer) The scoped_ptr
won't handle the deallocation because it hasn't been constructed yet.
Is this an oversight? Or is there a solution that I've failed to notice?
scoped_ptr
predates move semantics and is noncopyable by design. Thus, make_scoped
would be impossible to implement because in order to return an object from a function, its type must either be movable or copyable.
If the constructor fails, no memory is leaked. That's part of the semantics of new
, no smart pointers involved:
struct Foo { Foo() { throw 23; } };
new Foo(); // no memory leaked
The added exception safety provided by make_shared
comes from when you're initializing two shared_ptr
s in an expression and the two initializations are not sequenced, as is the case in function call arguments:
struct Bar {
Bar(bool fail) {
if(fail) throw 17;
}
}
f(shared_ptr<Bar>(new Bar(true)), shared_ptr<Bar>(new Bar(false)));
Since there is no sequencing between the evaluations of new Bar(true)
, shared_ptr<Bar>(new Bar(true))
, new Bar(false)
and shared_ptr<Bar>(new Bar(false))
, the following could happen:
new Bar(false)
is evaluated and succeeds: memory is allocated;new Bar(true)
is evaluated and fails: it doesn't leak memory resulting from this evaluation;No shared_ptr
was constructed at this time, and so the memory allocated in #1 is now leaked.
If Shoe throws then Shoe isn't constructed so there is nothing scoped_ptr can really do. No? The scoped_ptr x is on the stack and will get cleaned up on scope exit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With