Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does boost not have a make_scoped()?

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:

  • Allocate heap memory for Shoe
  • Call the constructor for Shoe
  • Call the constructor for 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?

like image 525
Drew Dormann Avatar asked Jul 05 '12 02:07

Drew Dormann


3 Answers

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.

like image 93
James McNellis Avatar answered Sep 17 '22 22:09

James McNellis


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_ptrs 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:

  1. new Bar(false) is evaluated and succeeds: memory is allocated;
  2. 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.

like image 42
R. Martinho Fernandes Avatar answered Sep 17 '22 22:09

R. Martinho Fernandes


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.

like image 32
emsr Avatar answered Sep 19 '22 22:09

emsr