I am working with a 3rd party C API set in C++ that has two methods of concern for this discussion:
- It's equivalent of malloc(): the_api_malloc(size) (plus a matching the_api_free())
- A function in which memory created with the_api_malloc() is returned to that takes ownership of it and the_api_free()'s it internally: the_api_give_back(ptr)
I have created a custom allocator wrapping the_api_malloc() and the_api_free() to use with for example std::vector. This works great.
What I'd like to do is have a std::vector type class that utilizes my custom allocator but also has a release() method that when called, releases ownership of it's memory and therefor will not call my custom allocators the_api_free().
pointer release() /* pointer is of T* */
Example usage:
MyClass myClass(1024); // the_api_malloc()'s 1024 bytes
// ... do something with myClass
the_api_give_back(myClass.release());
I'm not sure the best way to pull this off. What I have right now as a experiment is rather nasty:
class MyClass : public std::vector<char, MyAllocator<char> > {
public:
using typename std::vector<char, MyAllocator<char> >::pointer;
pointer release() {
// note: visual studio impl.
pointer p = this->_Myfirst;
this->_Myfirst = 0;
this->_Mylast = 0;
this->_Myend = 0;
return p;
}
}
Is there a better way?
UPDATE 1: Here is what I've tried based on suggestions below. This should also help illustrate desired behavior & where it is currently failing.
template <class T>
class MyAllocator
{
public:
// types omitted for clarity
MyAllocator() : m_released(false) { }
template <class U>
MyAllocator(MyAllocator<U> const& a) : m_released(a.m_released) { }
// other ctors, dtors, etc. omitted for clarity
// note: allocate() utilizes the_api_malloc()
void deallocate(pointer p, size_type num)
{
if(!m_released) {
the_api_free(p);
}
}
void release_ownership() { m_released = true; }
bool m_released;
};
template <typename T>
char* ReleaseOwernship(T& container)
{
container.get_allocator().release_ownership();
return &container[0];
}
// usage:
{ // scope
std::vector<char, MyAllocator<char> > vec;
// ...do something to populate vec...
char* p = ReleaseOwnership(vec);
the_api_give_back(p); // this API takes ownership of p and will delete it itself
} // end scope - note that MyAllocator::deallocate() gets called here -- m_release is still false
UPDATE 2: Tried creating a MyOwningAllocator and a MyNonOwningAllocator then swapping from the owning to the non-owning where at "release time", but can't get swap() to work as they are different types.