Skip to content
This repository has been archived by the owner on Mar 21, 2024. It is now read-only.

Commit

Permalink
vector_base: fix memory leak in reserve()
Browse files Browse the repository at this point in the history
Currently, when using reserve() to actually grow the
storage in a vector, a new backend storage is allocated,
but the old one is never deallocated. A more minor unexpected
behavior that also occurred is that the vector would still apply
its exponential growth behavior, ie., it when taking a vector of
size 3 and calling `.reserve(4)` on it, one would actually end up
with a vector of size 6.

The logic to allocate the new storage, copy in the existing elements,
then destroy the old elements and swap in the new storage (which does
to the old storage being destructed and hence deallocated) is, essentially,
taken from how `.resize()` works. When growing a vector using `.reserve()`,
the new capacity will now be exactly what was specified in the call to
`.reserve()`.
  • Loading branch information
germasch committed May 28, 2021
1 parent 1af5d90 commit 7abd42b
Showing 1 changed file with 32 additions and 1 deletion.
33 changes: 32 additions & 1 deletion thrust/detail/vector_base.inl
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,38 @@ template<typename T, typename Alloc>
{
if(n > capacity())
{
allocate_and_copy(n, begin(), end(), m_storage);
// compute the new capacity after the allocation
size_type new_capacity = n;

// do not exceed maximum storage
new_capacity = thrust::min THRUST_PREVENT_MACRO_SUBSTITUTION <size_type>(new_capacity, max_size());

// create new storage
storage_type new_storage(copy_allocator_t(), m_storage, new_capacity);

// record how many constructors we invoke in the try block below
iterator new_end = new_storage.begin();

try
{
// construct copy all elements into the newly allocated storage
new_end = m_storage.uninitialized_copy(begin(), end(), new_storage.begin());
} // end try
catch(...)
{
// something went wrong, so destroy & deallocate the new storage
new_storage.destroy(new_storage.begin(), new_end);
new_storage.deallocate();

// rethrow
throw;
} // end catch

// call destructors on the elements in the old storage
m_storage.destroy(begin(), end());

// record the vector's new state
m_storage.swap(new_storage);
} // end if
} // end vector_base::reserve()

Expand Down

0 comments on commit 7abd42b

Please sign in to comment.