user964970
user964970

Reputation:

Wrap C allocation for RAII

I've these plain C functions from a library:

struct SAlloc;
SAlloc *new_salloc();
void   free_salloc(SAlloc *s);

Is there any way I can wrap this in C++ to a smart pointer (std::unique_ptr), or otherwise a RAII wrapper ?

I'm mainly curious about the possibilities of the standard library without creating my own wrapper/class.

Upvotes: 7

Views: 2085

Answers (4)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275650

Another variation:

#include <memory>

struct SAlloc {
  int x;
};
SAlloc *new_salloc() { return new SAlloc(); }
void   free_salloc(SAlloc *s) { delete s; }

struct salloc_freer {
  void operator()(SAlloc* s) const { free_salloc(s); }
};
typedef std::unique_ptr<SAlloc, salloc_freer> unique_salloc;
template<typename... Args>
unique_salloc make_salloc(Args&&... args) {
  auto retval = unique_salloc( new_salloc() );
  if(retval) {
    *retval = SAlloc{std::forward<Args>(args)...};
  }
  return retval;
}

int main() {
   unique_salloc u = make_salloc(7);
}

I included a body to SAlloc and the various functions to make it a http://sscce.org/ -- the implementation of those doesn't matter.

So long as you can see the members of SAlloc, the above will let you construct them like in an initializer list at the same time as you make the SAlloc, and if you don't pass in any arguments it will zero the entire SAlloc struct.

Upvotes: 0

utnapistim
utnapistim

Reputation: 27365

Is there any way I can wrap this in C++ to a smart pointer (std::unique_ptr), or otherwise a RAII wrapper ?

Yes. You need here a factory function, that creates objects initializing the smart pointer correctly (and ensures you always construct pointer instances correctly):

std::shared_ptr<SAlloc> make_shared_salloc()
{
    return std::shared_ptr<SAlloc>(new_salloc(), free_salloc);
}

// Note: this doesn't work (see comment from @R.MartinhoFernandes below)
std::unique_ptr<SAlloc> make_unique_salloc()
{
    return std::unique_ptr<SAlloc>(new_salloc(), free_salloc);
}

You can assign the result of calling these functions to other smart pointers (as needed) and the pointers will be deleted correctly.

Edit: Alternately, you could particularize std::make_shared for your SAlloc.

Edit 2: The second function (make_unique_salloc) doesn't compile. An alternative deleter functor needs to be implemented to support the implementation.

Upvotes: 0

Ben Hymers
Ben Hymers

Reputation: 26546

I like R. Martinho Fernandes' answer, but here's a shorter (but less efficient) alternative:

auto my_alloc = std::shared_ptr<SAlloc>(new_salloc(), free_salloc);

Upvotes: 3

R. Martinho Fernandes
R. Martinho Fernandes

Reputation: 234524

Yes, you can reuse unique_ptr for this. Just make a custom deleter.

struct salloc_deleter {
    void operator()(SAlloc* s) const {
        free_salloc(s); // what the heck is the return value for?
    }
}

using salloc_ptr = std::unique_ptr<SAlloc, salloc_deleter>;

Upvotes: 14

Related Questions