Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception in std::vector<>::emplace_back() safe?

What happens when an exception is thrown in std::vector<>::emplace_back()?

For example:

class Foo {
public:
  Foo(int bar) {
    if (bar == 4) throw std::exception("Something went wrong");
  }
}

and

std::vector<std::unique_ptr<Foo>> foo_list;
foo_list.emplace_back(new Foo(3));
try {
  foo_list.emplace_back(new Foo(4));
} catch (std::exception error) {
  // How bad is it?
}
// Whats inside foo_list now?

I would expect the vector to just contain the first Foo object.

Is this the case? And is this guaranteed by the standard?

And also: Could there be any memory leaks?

like image 513
Jan Rüegg Avatar asked Sep 23 '16 13:09

Jan Rüegg


1 Answers

I would expect the vector to just contain the first Foo object.

Is this the case? And is this guaranteed by the standard?

Yes. The comments above already explained that emplace_back never even gets called because the Foo constructor throws while initializing the arguments for the function.

But ...

And also: Could there be any memory leaks?

Yes, you are using the anti-pattern that I have described at Inserting into a container of smart pointers with emplace_back(new X) (also published in Overload Journal #134 - August 2016).

The problem happens when emplace_back needs to reallocate the vector and that fails due to running out of memory. The pointer passed into the function will be lost, and so you leak the Foo object. This can happen for the first insertion (where the Foo constructor doesn't throw):

foo_list.emplace_back(new Foo(3));

Never use emplace_back to insert raw pointers into a container of unique_ptr, instead use make_unique:

foo_list.emplace_back(std::make_unique<Foo>(3));

Or if you have to use C++11 then construct the unique_ptr and insert or emplace that, not a raw pointer:

foo_list.emplace_back(std::unique_ptr<Foo>(new Foo(3)));

This way the object is owned by a unique_ptr immediately, and so if an exception happens inside emplace_back the object will be destroyed correctly.

like image 113
Jonathan Wakely Avatar answered Sep 28 '22 10:09

Jonathan Wakely