如何解决如何使将函数包装在noexcept可检测的可调用对象中的类模板用作std :: unique_ptr自定义删除器?
是否可以使用对象类型和自由函数作为为std::unique_ptr
创建自定义删除器的参数?
我是模板的新手,来到这里:
#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;
}
错误:
<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
建议我使用函数指针(并且还将其扩展到std :: function):
但这增加了通过函数指针(或std :: function)添加抛出语句的可能性,编译器或静态分析器将无法检测到该指针。使用lambda进行参数设置将确保没有人可以在std :: unique_ptr的析构函数中添加throwing语句。这就是我所说的“ noexcept可检测的可调用对象”
我正在使用C ++ 17。
解决方法
这是在抱怨,因为不能将lambda用作模板参数(无论如何在C ++ 20之前)。否则,lambda是可以被 调用的对象,除非函数体抛出,否则它们不会抛出,不需要包装类。您只需要这样做就很尴尬:
auto myDeleter = [&x](Foo* v) { internal_foo_free(v); };
std::unique_ptr<Foo,decltype(myDeleter)> guard { create_foo(),myDeleter };
最初,我将此问题解释为“如果有人使用未标记为noexcept
的自定义删除器,我希望编译失败”。我问了一下,我想这就是为什么您编辑标题以包含该措辞的原因。
noexcept
是用于优化提示/文档的限定符。它完全在荣誉系统上。您可以直接将它们放入其中,并且您的源仍将编译(尽管静态分析器可能会抱怨)。如果要强制执行自定义删除器仅调用noexcept
函数,则在C ++ 17中,可以使用noexcept
运算符使用静态断言,如果表达式调用non-noexcept函数则返回false :
template <auto F>
struct NoExceptDeleter{
template <typename T>
void operator ()(T* arg) const noexcept {
static_assert(noexcept(F(arg)),"deleter must be marked noexcept");
F(arg);
}
};
void good_delete(foo* v) noexcept { free(v); }
std::unique_ptr<foo,NoExceptDeleter<good_delete>> good_guard { make_foo() };
void bad_delete(foo* v) { throw 0; }
std::unique_ptr<foo,NoExceptDeleter<bad_delete>> bad_guard { make_foo() }; // compile-error
因为这需要函数指针,所以在C ++ 17中,您只能将其与+
运算符衰减为函数指针的非捕获lambda一起使用:
auto good_lambda = [](foo* v) noexcept { free(v); }
std::unique_ptr<foo,NoExceptDeleter<+good_lambda>> lambda_guard;
演示:https://godbolt.org/z/vdEov3
如果您需要在lambda中进行捕获,则必须使用有状态的删除器:
template <typename F>
struct StatefulNoExceptDeleter {
F f;
StatefulNoExceptDeleter(F f) : f(f) { }
template <typename T>
void operator ()(T* arg) const noexcept {
static_assert(noexcept(f(arg)),"deleter must be marked noexcept");
f(arg);
}
};
/* ... */
int baz;
auto deleter = [&](Foo* t) noexcept {
std::cout << "labmda: " << baz << std::endl;
delete t;
};
std::unique_ptr<Foo,StatefulNoExceptDeleter<decltype(deleter)>> guard {
new Foo,StatefulNoExceptDeleter<decltype(deleter)>{ deleter }
};
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。