I wanted to create some smart pointers for sqlite3
using CHeapPtr
. CHeapPtr
uses the CCRTAllocator
class by default, so I figured I'd just create some custom allocator classes that inherit from CCRTAllocator
but override its Free
method, so that they use the proper clean-up functions:
class CSqlite3Allocator : public CCRTAllocator
{
public:
static void Free(_In_ sqlite3* p) throw()
{
sqlite3_close_v2(p);
}
};
class CSqlite3StmtAllocator : public CCRTAllocator
{
public:
static void Free(_In_ sqlite3_stmt* p) throw()
{
sqlite3_finalize(p);
}
};
Now I can create CHeapPtr
s like so:
CHeapPtr<sqlite3, CSqlite3Allocator> psqlite;
CHeapPtr<sqlite3_stmt, CSqlite3StmtAllocator> pstmt;
These pointers seem to work correctly, and it appears that their clean-up methods are being called. I was just wondering if this is the proper way of doing this, or if there's a more accepted way of creating custom CHeapPtr
s. Thank you for any input.
You don't need to inherit from CCRTAllocator
, allocator is expected to be just a new class. You can use ATL's COM heap allocator as an example:
class CComAllocator
{
public:
static void* Reallocate(void* p, size_t nBytes) throw()
{
return ::CoTaskMemRealloc(p, ULONG(nBytes));
}
static void* Allocate(size_t nBytes) throw()
{
return ::CoTaskMemAlloc(ULONG(nBytes));
}
static void Free(void* p) throw()
{
::CoTaskMemFree(p);
}
};
template <typename T>
class CComHeapPtr :
public CHeapPtr<T, CComAllocator>
{
public:
CComHeapPtr() throw()
{
}
explicit CComHeapPtr(T* pData) throw() :
CHeapPtr<T, CComAllocator>(pData)
{
}
};
(the code here is shortened a bit for brevity)
The way you implemented can work out but you inherit allocation/reallocation methods from CRT and it makes it a dangerous mix: unintentionally you can end up with CRT Allocate
and sqlite Free
and it might be hard to nail it down. If you don't plan to use allocation methods, you can just stub them or put ATLASSERT(FALSE)
there.