Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Destroy std::vector without releasing memory

Lets say I have a function to get data into an std vector:

void getData(std::vector<int> &toBeFilled) {
  // Push data into "toBeFilled"
}

Now I want to send this data to another function, that should free the data when finished:

void useData(int* data)
{
  // Do something with the data...
  delete[] data;
}

Both functions (getData and useData) are fixed and cannot be changed. This works fine when copying the data once:

{
  std::vector<int> data;
  getData(data);
  int *heapData = new int[data.size()];
  memcpy(heapData, data.data(), data.size()*sizeof(int));
  useData(heapData);
  data.clear();
}

However, this memcpy operation is expensive and not really required, since the data is already on the heap. Is it possible to directly extract and use the data allocated by the std vector? Something like (pseudocode):

{
  std::vector<int> data;
  getData(data);
  useData(data.data());
  data.clearNoDelete();
}

Edit:

The example maybe doesn't make too much sense, since it is possible to just free the vector after the function call to useData. However, in the real code, useData is not a function but a class that receives the data, and this class lives longer than the vector...

like image 916
Jan Rüegg Avatar asked Oct 23 '14 09:10

Jan Rüegg


People also ask

How do you destroy a vector in C++?

The C++ function std::vector::clear() destroys the vector by removing all elements from the vector and sets size of vector to zero.

How do I clear a vector memory?

clear() removes all the elements from a vector container, thus making its size 0. All the elements of the vector are removed using clear() function.

Does vector automatically deallocate memory?

If you declare a std::vector in a specific scope, when that scope is no longer valid the std::vector memory will be destructed and freed automatically. Strategies like SBRM reduce the chance of introducing memory leaks. In summary: std::vector simplifies much of the overhead code required to manage dynamic arrays.

Can you delete a vector C++?

One way of deleting a vector is to use the destructor of the vector. In this case, all the elements are deleted, but the name of the vector is not deleted. The second way to delete a vector is just to let it go out of scope. Normally, any non-static object declared in a scope dies when it goes out of scope.


2 Answers

No.

The API you're using has a contract that states it takes ownership of the data you provide it, and that this data is provided through a pointer. This basically rules out using standard vectors.

Vector will always assuredly free the memory it allocated and safely destroy the elements it contains. That is part of its guaranteed contract and you cannot turn that off.

You have to make a copy of the data if you wish to take ownership of them... or move each element out into your own container. Or start with your own new[] in the first place (ugh) though you can at least wrap all this in some class that mimics std::vector and becomes non-owning.

like image 92
Lightness Races in Orbit Avatar answered Sep 26 '22 18:09

Lightness Races in Orbit


Here's a horrible hack which should allow you to do what you need, but it relies on Undefined Behaviour doing the simplest thing it can. The idea is to create your own allocator which is layout-compatible with std::allocator and type-pun the vector:

template <class T>
struct CheatingAllocator : std::allocator<T>
{
  using typename std::allocator<T>::pointer;
  using typename std::allocator<T>::size_type;

  void deallocate(pointer p, size_type n) { /* no-op */ }

  // Do not add ANY data members!!
};


{
  std::vector<int, CheatingAllocator<int>> data;
  getData(reinterpret_cast<std::vector<int>&>(data)); // type pun, `getData()` will use std::allocator internally
  useData(data.data());
  // data actually uses your own allocator, so it will not deallocate anything
}

Note that it's as hacky and unsafe as hacks go. It relies on the memory layout not changing and it relies of std::allocator using new[] inside its allocate function. I wouldn't use this in production code myself, but I believe it is a (desperate) solution.


@TonyD correctly pointed out in the comments that std::allocator is quite likely to not use new[] internally. Therefore, the above would most likely fail on the delete[] inside useData(). The same @TonyD also made a good point about using reserve() to (hopefully) prevent reallocation inside getData(). So the updated code would look like this:

template <class T>
struct CheatingAllocator : std::allocator<T>
{
  using typename std::allocator<T>::pointer;
  using typename std::allocator<T>::size_type;

  pointer allocate(size_type n) { return new T[n]; }

  void deallocate(pointer p, size_type n) { /* no-op */ }

  // Do not add ANY data members!!
};


{
  std::vector<int, CheatingAllocator<int>> data;
  data.reserve(value_such_that_getData_will_not_need_to_reallocate);
  getData(reinterpret_cast<std::vector<int>&>(data)); // type pun, `getData()` will use std::allocator internally
  useData(data.data());
  // data actually uses your own allocator, so it will not deallocate anything
}
like image 35
Angew is no longer proud of SO Avatar answered Sep 24 '22 18:09

Angew is no longer proud of SO