Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ exception safety in constructor

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?

like image 409
CoffeDeveloper Avatar asked Jun 28 '13 00:06

CoffeDeveloper


People also ask

Is it safe to throw exception in constructor?

The short answer to the question “can a constructor throw an exception in Java” is yes!

How do you handle exceptions in constructor?

When throwing an exception in a constructor, the memory for the object itself has already been allocated by the time the constructor is called. So, the compiler will automatically deallocate the memory occupied by the object after the exception is thrown.

Can we handle exception in constructor in C++?

In C++, exceptions are used to signal errors that cannot be handled locally, such as the failure to acquire a resource in a constructor.

Is destructor called when exception is thrown in constructor?

When an exception is thrown from a constructor, the object is not considered instantiated, and therefore its destructor will not be called. But all destructors of already successfully constructed base and member objects of the same master object will be called.


1 Answers

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:

  1. Evaluate the expression new Foo()
  2. Evaluate the expression new Bar()
  3. Construct the std::unique_ptr<Foo> temporary from the result of 1.
  4. 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.

like image 89
Andy Prowl Avatar answered Oct 03 '22 14:10

Andy Prowl