Reputation: 638
First of all, my motivation is to do efficient memory management on top of a C like computational kernel. And I tried to use the std::unique_ptr
and std::vector
, my code looks like below
// my data container
typedef std::unique_ptr<double> my_type;
std::vector<my_type> my_storage;
// when I need some memory for computation kernel
my_storage.push_back(my_type());
my_storage.back.reset(new double[some_length]);
// get pointer to do computational stuff
double *p_data=my_storage.back.get();
Notice here in practice p_data
may be stored in some other container(e.g. map) to indexing each allocated array according to the domain problem, nevertheless, my main questions are
Here is std::vector
a good choice? what about other container like std::list
/set
?
Is there fundamental problem with my allocation method?
Suppose after I use p_data
for some operations, now I want to release the memory chunk pointed by the raw pointer p_data
, what is the best practice here?
Upvotes: 2
Views: 892
Reputation: 133577
First of all, if you are allocating an array you need to use the specialization std::unique_ptr<T[]>
or you won't get a delete []
on memory release but a simple delete
.
std::vector
is a good choice unless you have any explicit reason to use something different. For example, if you are going to move many elements inside the container then a std::list
could perform better (less memmove
operations to shift things around).
Regarding how to manage memory, it depends mainly on the pattern of utilization. If my_storage
is mainly responsible for everything (which in your specification it is, since unique_ptr
expresses ownership), it means that it will be the only one who can release memory. Which could be done simply by calling my_storage[i].reset()
.
Mind that storing raw pointers of managed objects inside other collections leads to dangling pointers if memory is released, for example:
using my_type = std::unique_ptr<double[]>;
using my_storage = std::vector<my_type>;
my_storage data;
data.push_back(my_type(new double[100]));
std::vector<double*> rawData;
rawData.push_back(data[0].get());
data.clear(); // delete [] is called on array and memory is released
*rawData[0] = 1.2; // accessing a dangling pointer -> bad
This could be a problem or not, if data
is released by last then there are no problems, otherwise you could store const references to std::unique_ptr
so that at least you'd be able to check if memory is still valid, e.g.:
using my_type = std::unique_ptr<double[]>;
using my_managed_type = std::reference_wrapper<const my_type>;
std::vector<my_managed_type> rawData;
Upvotes: 2
Reputation: 596352
Using std::unique_ptr
with any STL container , including std::vector
, is fine in general. But you are not using std::unique_ptr
the correct way (you are not using the array specialized version of it), and you don't need to resort to using back.reset()
at all. Try this instead:
// my data container
typedef std::unique_ptr<double[]> my_type;
// or: using my_type = std::unique_ptr<double[]>;
std::vector<my_type> my_storage;
my_type ptr(new double[some_length]);
my_storage.push_back(std::move(ptr));
// or: my_storage.push_back(my_type(new double[some_length]));
// or: my_storage.emplace_back(new double[some_length]);
Upvotes: 1