问题
What about following code
MyClass a(new Foo(), new Bar());
if "new Foo()" is successful, but "new Bar()" throws, will Foo leak?
Is taking
std::unique_ptr<Foo>
or
std::shared_ptr<Foo>
as parameters, enough to prevent the leak?
回答1:
if "new Foo()" is successful, but "new Bar()" throws, does Foo will leak?
Yes.
Is taking [...] as parameters, enough to prevent the leak?
Not necessarily. It depends on how you pass the parameters. For instance, even supposed your class constructor looks like this:
MyClass::MyClass(std::unique_ptr<Foo> foo, std::unique_ptr<Bar> bar)
The following may still cause a leak:
MyClass a(std::unique_ptr<Foo>(new Foo()), std::unique_ptr<Bar>(new Bar())
That is because the compiler may is allowed to evaluate the above expressions in the following order:
- Evaluate the expression
new Foo() - Evaluate the expression
new Bar() - Construct the
std::unique_ptr<Foo>temporary from the result of 1. - Construct the
std::unique_ptr<Bar>temporary from the result of 2.
If 2) throws an exception, you've lost your Foo.
However, it is possible to make this safe by using std::make_unique<>() (C++14 only) or std::make_shared<>(), like so:
MyClass a(std::make_unique<Foo>(), std::make_unique<Bar>());
Now no leak could possibly happen, because std::make_unique<>() (and std::make_shared<>()) immediately associate the object they create to the corresponding smart pointer, without these two operations (dynamic allocation and construction of the smart pointer) being interleaved with any other operation.
来源:https://stackoverflow.com/questions/17355331/c-exception-safety-in-constructor