2

Is there a generic handle class in STL or boost? I am interfacing with some C code that has an alloc, release api. I'd like to use a handle to auto release resource.

For example:

some_resource_type rsc;  
int err = capi_alloc(&rsc);
if (err != NOERR) {
   // .. do work with resource

   capi_release(rsc);
}  

I want something like

// looking for this class
class wrapper { 
public:
     wrapper(T obj, void (del)(T&)):obj(obj_),del_(del) {}
     ~wrapper() {_del(obj);}
     T obj_;
     void (del_)(T&);
};

some_resource_type rsc;  
int err = capi_alloc(&rsc);
wrapper w;
if (err != NOERR) {
    w = wrapper(rsc, &capi_release);
    // .. do work with resource
}  
// then auto release

anything like this in STL or boost? It's essentially some unique pointer implementation with custom create and custom delete.

P.S. I haven't compiled the wrapper code, it may not work.

Candy Chiu
  • 6,579
  • 9
  • 48
  • 69

3 Answers3

1

What you want is a smart pointer, and these are in recent C++ and in almost all in-the-wild meetable Boost variants; if you're using C++11, replace boost by std:

  • boost::shared_ptr
  • boost::weak_ptr
Emil Laine
  • 41,598
  • 9
  • 101
  • 157
Marcus Müller
  • 34,677
  • 4
  • 53
  • 94
  • Smart pointers would allocate `some_resource_type` dynamically. As I understood it, the OP wants to allocate it on the stack. – Emil Laine Jul 10 '15 at 22:36
  • You're right: if you declare your smart ptr on the stack, the thing it points at must be allocated off the heap. When the smart ptr goes out of scope it automatically cleans up the memory. – Brian Vandenberg Jul 10 '15 at 22:43
  • @zenith, and as Brian hinted to, that includes calling the destructor of your object, which might free whatever external ressource your object was keeping. – Marcus Müller Jul 10 '15 at 22:44
  • Smart pointers don't allocate anything at all. You give them already-allocated data and tell them how to delete it, and they simply clean up for you when they go out of scope. – celticminstrel Jul 11 '15 at 00:44
1

You can actually (ab)use std::unique_ptr and its second template parameter (custom deallocator) for this:

std::unique_ptr<some_resource_type, void (&)(some_resource_type*)> w(nullptr, &capi_release);

And then in your if:

w.reset(&rsc);

A word of warning however: you must declare w after rsc with this approach. Otherwise rsc will be destroyed before w calls capi_release with it.

However since this is not the intended usage of unique_ptr I would recommend simply writing a small wrapper class as demonstrated in my other answer.

Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • I tried this too, also works. thanks. I simplified the definition to std::unique_ptr w(nullptr, &capi_release); I hope you see that this question is helpful since the other one, although similar, does not include a generic answer. – Candy Chiu Jul 11 '15 at 02:28
0

Since std::unique_ptr only supports heap allocation and no custom allocators, you could roll up your own stack-based wrapper class:

template<class T, int (& Allocator)(T*), void (& Deallocator)(T*)>
class wrapper {
public:
    wrapper() : err_(Allocator(&obj_)) {}
    ~wrapper() { if (err_ != NOERR) Deallocator(&obj_); }
    T& obj() { return obj_; }
    int err() { return err_; }
private:
    T obj_;
    int err_;
};

And use it like this:

wrapper<some_resource_type, capi_alloc, capi_release> rsc;  // capi_alloc called
if (rsc.err() != NOERR) {
    // .. do work with rsc.obj()
}
// capi_release called when rsc goes out of scope (if err_ != NOERR)

If you don't know what the allocator and deallocator functions are at compile time, then just pass them to the constructor and store as member data.

Emil Laine
  • 41,598
  • 9
  • 101
  • 157