I'm using a C function that has a signature like:
/**
* Read values from source file and store in a newly
* allocated array
*/
size_t load_array(FILE * source, double ** pdest) {
size_t values_read;
double * dest;
// ...
// Keep reading in values from source, incrementing values_read
// resizing dest when needed.
// ...
*pdest = dest;
return values_read;
}
which currently gets called in my C++ code like this:
double * my_array;
size_t array_length = load_array(source, &my_array);
// ... do stuff with my_array ...
free(my_array);
Can I wrap up my_array
with std::unique_ptr
so that free
gets automatically called? I cannot change the C function (which is part of an external library) so I cannot change the data structure used therein.
There is a similar question on SO, but in that question the C function returned a pointer, and a unique_ptr
was created around this returned value. Some of the suggested answers would work if a dumb pointer was created first and then wrapped later, e.g.:
double * my_array;
size_t array_length = load_array(source, &my_array);
auto my_array_wrapper = std::unique_ptr<double, decltype(free)*>{ my_array, free };
// ... do stuff with my_array_wrapper ...
// free() called on wrapped pointer when my_array_wrapper goes out of scope
This doesn't seem very clean to me, since I would still have the original pointer lying around in my code. What I would like to do to completely contain the pointer, with something like:
clever_ptr my_clever_array;
size_t array_length = load_array(source, my_clever_array.get_ptr_address());
// ... do stuff with my_clever_array ...
// free() called on wrapped pointer when wrapper goes out of scope
Obviously I could write a small class for this, but I'm interested in whether there are existing utilities that already provide for this.
Turns out this can't be done the std::unique_ptr
. The only methods for getting at a pointer from this class are:
pointer get() const noexcept;
which, being const
, won't allow the value of the managed pointer to change (the returned pointer is not const
, but it is a copy of the managed one, so changing it's value will not change the value inside the unique_ptr
) pointer release() noexcept;
which releases ownership of the managed pointer and so will not call free
on it when it goes out of scope.Hence the only route is to wrap up the pointer after it has been updated. To avoid leaving the pointer lying around it could be placed in a block to limit its scope:
std::unique_ptr<double, decltype(free)*> my_array_wrapper{nullptr, free};
{
double * my_array;
size_t array_length = load_array(source, &my_array);
my_array_wrapper = std::unique_ptr<double, decltype(free)*>{ my_array, free };
}
// ... do stuff with my_array_wrapper ...
// free() called on wrapped pointer when wrapper goes out of scope
This could probably be extended with a wrapper for the load_array
function:
size_t load_array_wrapped(FILE * source, std::unique_ptr<double, decltype(free)*> & array_wrapper) {
double * my_array;
size_t array_length = load_array(source, &my_array);
my_array_wrapper = std::unique_ptr<double, decltype(free)*>{ my_array, free };
return array_length;
}
and then call with:
std::unique_ptr<double, decltype(free)*> my_array_wrapper{nullptr, free};
size_t array_length = load_array_wrapped(source, my_array_wrapper);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With