Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe to use vector.emplace_back( new MyPointer ); Could failure inside vector lead to leaked memory?

Is it safe to use

vector.emplace_back( new MyPointer() );

Or could an exception thrown or some failure inside vector cause memory leak?

Would it be better to do some form of the following, where you put the pointer in a temporary unique_ptr first.

vector.emplace_back( std::unique_ptr<MyPointer>( new MyPointer() ) );

So if a vector failure occurs the temporary unique_ptr will still clean up the memory?

like image 874
EddieV223 Avatar asked Oct 16 '13 21:10

EddieV223


2 Answers

It is not safe and would create a memory leak if you use the first version. The documentation says that if an exception is thrown, the call to emplace has no effect - which means the plain pointer you passed in is never deleted.

You can use

vector.emplace_back( std::unique_ptr<MyPointer>( new MyPointer() ) );

or with C++14 you can use

vector.emplace_back( std::make_unique<MyPointer>() );

or, if C++14 is not yet available, just roll your own version of make_unique. You can find it here.

like image 114
Daniel Frey Avatar answered Oct 22 '22 13:10

Daniel Frey


No, the first scenario is not safe and will leak memory if the vector throws an exception.

The second scenario will not compile, as a std::unique_ptr<T> cannot be implicitly converted to T*. Even if it could, this scenario is arguably worse than the first, because it will add the pointer to your vector, then immediately delete the object being pointed to. You will be left with a vector containing a dangling pointer.

Without changing the type of your std::vector (which I assume is std::vector<MyPointer*>) there are two ways to make this code exception safe.

Using C++11:

auto ptr = std::unique_ptr<MyPointer>(new MyPointer());
vector.emplace_back(ptr.get());
ptr.release();

Or the more verbose C++03 way:

MyPointer* ptr = new MyPointer();
try
{
  vector.push_back(ptr);
}
catch (...)
{
  delete ptr;
  throw;
}

If you are able to change the type of your std::vector<MyPointer*> then the easiest method are those suggested by Daniel Frey above:

std::vector<std::unique_ptr<MyPointer>> vector;
vector.emplace_back(std::unique_ptr<MyPointer>(new MyPointer()));

Or with C++14:

std::vector<std::unique_ptr<MyPointer>> vector;
vector.emplace_back(std::make_unique<MyPointer>()); 
like image 31
marack Avatar answered Oct 22 '22 11:10

marack