The original question (and hvd's answer) introduce a per-pointer overhead, so such a unique_ptr
is twice the size than one derived with std::make_unique
. In addition, I would formulate the decltype directly:
std::unique_ptr<char, decltype(&std::free)>
t_copy { strdup(t), &std::free };
If one has many of those C-API-derived pointers that extra space can be a burden hindering adoption of safe C++ RAII for C++ code wrapping existing POSIX style APIs requiring to be free()
d. Another problem that can arise, is when you use char const
in the above situation, you get a compile error, because you can not automatically convert a char const *
to the Parameter type of free(void *)
.
I suggest to use a dedicated deleter type, not one built on the fly, so that the space overhead goes away and the required const_cast
is also not a problem. A template alias then can easily be used to wrap C-API-derived pointers:
struct free_deleter{
template <typename T>
void operator()(T *p) const {
std::free(const_cast<std::remove_const_t<T>*>(p));
}
};
template <typename T>
using unique_C_ptr=std::unique_ptr<T,free_deleter>;
static_assert(sizeof(char *)==
sizeof(unique_C_ptr<char>),""); // ensure no overhead
The example now becomes
unique_C_ptr<char const> t_copy { strdup(t) };
I will suggest that that mechanism should be made available in the C++ Core Guidelines support library ( maybe with a better naming ), so it can be made available for code bases transitioning to modern C++ ( success open ).