7

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.

4 Answers4

14

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>;
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
  • 1
    `free_salloc` is not a type, so no. You could use `std::unique_ptr;`, but then you would have to pass `free_salloc` manually to every constructor. – R. Martinho Fernandes Feb 11 '13 at 09:05
  • Return-value with RAII doesn't make sense. They're incompatible ideas. +1 BTW! – Nawaz Feb 11 '13 at 09:09
  • Thanks for the answer. I had asked whether `std::unique_ptr` would work too but realized the mistake directly after posting, so I deleted my comment. – Medo42 Feb 11 '13 at 09:27
  • You do not need a salloc_deleter functor - you can just pass the free_salloc function as a deleter (see my answer below). – utnapistim Feb 11 '13 at 09:43
  • 1
    You can use `std::integral_constant` here, see [this answer](http://stackoverflow.com/a/30166010/343443) for details. – Abyx May 29 '15 at 16:19
3

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);
Ben Hymers
  • 25,586
  • 16
  • 59
  • 84
0

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.

utnapistim
  • 26,809
  • 3
  • 46
  • 82
  • `free_salloc` is not an instance of `default_delete `, so the second function won't compile. – R. Martinho Fernandes Feb 11 '13 at 09:45
  • @R.MartinhoFernandes, I am not sure what you mean by "instance of default_delete". The shared_ptr/unique_ptr work with any deleter functor. The `default_delete` and `default_array_delete` are simple functors, with no special requirements and can be replaced by any other functor types that respect the same signatures. See here as an example of what the OP was asking: http://liveworkspace.org/code/16bBch$6 – utnapistim Feb 11 '13 at 09:53
  • That's wrong. unique_ptr only works with deleters of type D. unique_ptr only works with deleters of type default_delete: http://liveworkspace.org/code/23jdye$0 – R. Martinho Fernandes Feb 11 '13 at 09:54
0

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.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524