Is it possible to use object type and free functions as parameters for creating custom deleters for std::unique_ptr ?
I'm new to templates and came up till here:
#include <memory>
template<typename T, typename FreeFunc> struct ObjectDeleter {
const FreeFunc &free_func;
ObjectDeleter(const FreeFunc &free_func) : free_func(free_func){
}
void operator()(T *item)
{
if (item) {
free_func(item);
}
}
};
struct Foo{};
void internal_foo_free(Foo *){}
struct Bar{};
void internal_bar_free(Bar *){}
using unique_foo_ptr =
std::unique_ptr<Foo, ObjectDeleter<Foo>([](Foo *foo){internal_foo_free(foo);});
int main(){
return 0;
}
error:
<source>:19:48: error: wrong number of template arguments (1, should be 2)
19 | std::unique_ptr<Foo, ObjectDeleter<Foo>([](Foo *foo){internal_foo_free(foo);});
| ^
<source>:3:48: note: provided for 'template<class T, class FreeFunc> struct ObjectDeleter'
3 | template<typename T, typename FreeFunc> struct ObjectDeleter {
| ^~~~~~~~~~~~~
<source>:19:50: error: lambda-expression in template-argument only available with '-std=c++2a' or '-std=gnu++2a'
19 | std::unique_ptr<Foo, ObjectDeleter<Foo>([](Foo *foo){internal_foo_free(foo);});
| ^
<source>:19:87: error: template argument 2 is invalid
19 | std::unique_ptr<Foo, ObjectDeleter<Foo>([](Foo *foo){internal_foo_free(foo);});
| ^
Compiler returned: 1
I was suggested to use function pointer (and I extend it to std::function also):
but that adds the possibility of adding throwing statements via the function pointer (or std::function), which the compiler or static analysers won't be able to detect. Parameterising using lambda will make sure that the no-one can add throwing statements in the destructor of std::unique_ptr. This is what I mean by "noexcept-detectable, callable object"
I'm using C++17.
It's complaining because lambdas can't be used as template arguments (before C++20 anyway). Otherwise, lambdas are already callable objects that will not throw unless the function body throws, no wrapper class needed. You just have to do this awkwardness:
Originally, I interpreted this question as "I want compilation to fail if someone uses a custom deleter not marked
noexcept". I asked about it, which I think is why you edited your title to include that wording.noexceptis a qualifier for optimization hint/documentation purposes. It is totally on the honor system. You can throw right inside them, and your source will still compile (though a static analyzer might complain). If you wanted to enforce that a custom deleter only callsnoexceptfunctions, in C++17 you can use a static assertion with thenoexceptoperator, which returns false if an expression calls a non-noexcept function:Because this takes a function pointer, in C++17 you can only use it with non-capturing lambdas decayed to a function pointer with the
+operator:Demo: https://godbolt.org/z/vdEov3
If you needed to capture inside your lambda, you'd have to use a stateful deleter: