Implementing `create` and `destroy` functions to replace `new` and `delete` operators The environment I'm working in requires that all allocation is done through a special set of malloc/calloc functions and that a user ID is provided when allocating. The environment has no implementation of exceptions, so errors are signaled by returning NULL.

For this reason, I have tried to write a couple of C++ functions which make it easier to create and destroy C++ objects:

namespace details {
    template&lt;typename T&gt;
    typename enable_if&lt;is_pod&lt;T&gt;::value, T&gt;::type *
    create(uint32_t module_id) {
        // use module_id
        return (T *)calloc(1, sizeof(T));
    }

    template&lt;typename T, typename ...Args&gt;
    typename enable_if&lt;!is_pod&lt;T&gt;::value, T&gt;::type *
    create(uint32_t module_id, Args&amp;&amp;... args) {
        // use module_id
        T *p = (T *)calloc(1, sizeof(T));
        if (p)
            new (p) T(forward&lt;Args&gt;(args)...);
        return p;
    }

    template&lt;typename T&gt;
    void destroy(typename enable_if&lt;is_pod&lt;T&gt;::value, T&gt;::type *t) {
        if (t)
            free(t);
    }

    template&lt;typename T&gt;
    void destroy(typename enable_if&lt;!is_pod&lt;T&gt;::value, T&gt;::type *t) {
        if (!t)
            return;

        t-&gt;~T();
        free(t);
    }
};

template&lt;typename T, typename ...Args&gt;
T *create(uint32_t module_id, Args&amp;&amp;... args) {
    return details::create&lt;T&gt;(module_id, forward&lt;Args&gt;(args)...);
}

template&lt;typename T&gt;
void destroy(T *t) {
    details::destroy&lt;T&gt;(t);
}


Can this be done smarter?  And are there any cases where my create/destroy functions are not handling as one would expect?
After some research, I'm convinced Christopher Creutzig is right. If you want all your allocations to go through customized functions, you're much better off replacing the global operator new. This will catch all calls to new for the translation unit, whether you replace them with create or not. That means when you create a std::vector&lt;T&gt; myvec(3), it will use your operator new for any heap allocations it needs to do, instead of sidestepping your global policy.

If you need to pass a module id, operator new can handle that as well by accepting extra parameters. I'm unclear how that mixes with examples such as the std::vector&lt;T&gt; heap allocations; it may require using a custom allocator for each STL container. Setting that aside, here's an example like yours following the lead on cppreference.com:

void* operator new(std::size_t cb, uint32_t module_id)
{
    // use module_id
    return calloc(1, cb);
}
void operator delete(void* ptr)
{
    free(ptr);   // I'm unsure if this requires a null check
}

type *p = new(module_id) type;


As an aside, if you're particularly tied to calling functions, I'd be tempted to remove the SFINAE specialization via is_pod&lt;T&gt; and just make it an inline check via is_trivially_constructible&lt;T&gt; and is_trivially_destructible&lt;T&gt;...that is if checking is necessary at all.

template&lt;typename T&gt;
T* create(uint32_t module_id)
{
    // use module_id
    T* p = calloc(1, sizeof(T));
    if (!is_trivially_constructable&lt;T&gt;::value &amp;&amp; p)
    {
        new (p) T(forward&lt;Args&gt;(args)...);
    }
    return p;
}