Search code examples
c++winapismart-pointersatlallocator

Creating a custom allocator for CHeapPtr (for use with Sqlite)


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 CHeapPtrs 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 CHeapPtrs. Thank you for any input.


Solution

  • 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.