Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unique_ptr handling for double pointer

Tags:

c++

unique-ptr

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.

like image 541
beldaz Avatar asked Oct 31 '22 07:10

beldaz


1 Answers

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);
like image 65
beldaz Avatar answered Nov 15 '22 05:11

beldaz