为什么这段代码会出现"exception spec is more lax than base"错误?
Why do I get "exception spec is more lax than base" error with this piece of code?
试图使用Xcode 6.1中的clang版本(clang-600.0.54基于LLVM 3.5svn),使用-std=c++11
和-stdlib=libc++
编译以下代码,这给了我一些我不太理解的错误。
#include <functional>
struct Impl
{
typedef std::function<void ()> L;
L l;
int i;
};
struct Hndl
{
Impl* impl;
Hndl(Impl* i): impl(i) {}
~Hndl() noexcept(false) {}
};
int main(int argc, char * argv[]) {
Hndl h(new Impl());
h.impl->l = [=]
{
h.impl->i = 42;
};
return 0;
}
结果:
In file included from t.cpp:1:
/Applications/Xcode-6.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1293:52: error: exception specification of overriding
function is more lax than base version
template<class _FD, class _Alloc, class _FB> class __func;
^
/Applications/Xcode-6.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1593:13: note: in instantiation of template class
'std::__1::__function::__func<<lambda at t.cpp:20:14>, std::__1::allocator<<lambda at t.cpp:20:14> >, void ()>' requested here
if (sizeof(_FF) <= sizeof(__buf_) && is_nothrow_copy_constructible<_Fp>::value)
^
/Applications/Xcode-6.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1697:5: note: in instantiation of function template
specialization 'std::__1::function<void ()>::function<<lambda at t.cpp:20:14> >' requested here
function(_VSTD::forward<_Fp>(__f)).swap(*this);
^
t.cpp:20:12: note: in instantiation of function template specialization 'std::__1::function<void ()>::operator=<<lambda at t.cpp:20:14> >' requested here
h.impl->l = [=]
^
/Applications/Xcode-6.1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:1281:39: note: overridden virtual function is here
_LIBCPP_INLINE_VISIBILITY virtual ~__base() {}
^
1 error generated.
看起来Impl::L::~L()
以某种方式继承了Hndl::~Hndl()
的noexcept(false)
,但我不知道为什么。有趣的是,如果我注释掉lambda中h.impl->i
的赋值,则编译相同的代码。如果我从Hndl::~Hndl()
中删除noexcept(false)
规范,也会编译,但我需要它(解释原因可能有点长,但我确实需要)。如果lambda通过ref捕获,也会进行编译,但这里的重点是能够复制共享实现的句柄。将noexcept(true)
添加到Impl::~Impl()
没有帮助。
ideone.com的c++11编译器很乐意按原样编译它。
有人能解释一下这里发生了什么吗?
lambda捕获h
,它有一个潜在的抛出析构函数,因此lambda的闭包类型也有一个可能抛出的析构函数。
考虑到这一点,您可以将问题简化为:
#include <functional>
struct F
{
void operator()() { }
~F() noexcept(false) {}
};
int main() {
std::function<void ()> f = F{};
}
似乎libc++中的std::function
无法在没有nothrow析构函数的情况下存储可调用类型,这看起来像是libc++中一个bug。
从错误消息来看,修复可能就像向__func
析构函数添加一个显式noexcept
一样简单,但我不熟悉实现,所以可能没有那么容易。
除了用noexcept
析构函数将Hndl
类型封装在另一个类型中之外,我看不到任何明显的解决方法,因此在lambda中捕获它不会使lambda具有noexcept(false)
析构函数。我尝试过这样的方法,但libc++在shared_ptr
:中似乎也有类似的问题
std::function<void ()> f = std::bind(&Hndl::operator(), std::make_shared<Hndl>());
我认为问题是Hndl
在lambda中按值捕获,而std::function
析构函数被视为noexcept(true)
,因为它的定义中没有另行说明。因此Hndl
实例不能在l
析构函数中被安全地销毁。至于若从lambda中移除成员赋值,为什么错误会消失——很可能捕获的值只是被编译器优化掉了。
以下是一个可能的解决方法,基于http://www.codeproject.com/Articles/313312/Cplusplus-Lambda-Storage-Without-libcplusplus
请注意,以下代码是为了演示而简化的;它是不完整的,并且只处理void()lambdas。请参阅上面的链接了解真实情况(尽管在我的特殊情况下,void()就足够了)。
#include <functional>
struct Lambda
{
void* lambda;
void (*execute)(void*);
template <typename T> Lambda& operator=(T&& t)
{
lambda = new T(t);
execute = [](void* lambda) { ((T*)lambda)->operator()(); };
return *this;
}
void operator()() { execute(lambda); }
};
// ---
struct Impl
{
Lambda l;
int i;
};
struct Hndl
{
Impl* impl;
Hndl(Impl* i): impl(i) {}
~Hndl() noexcept(false) {}
};
int main(int argc, char * argv[]) {
Hndl h(new Impl());
h.impl->l = [=]
{
h.impl->i = 42;
};
h.impl->l();
return 0;
}
- Why is UINT32_MAX + 1 = 0?
- C++错误:"error: int aaa::bbb is protected within this context"
- 创建具有 new in 函数和"this is nullptr"异常的对象
- 使用 cmake 的 Linux 终端上的"Conversion to non-scalar type is requested"错误
- Is !NaN not a NaN?
- Directx 11 - CompileFromFile() is not compiling
- Centos7 g++ "to_string is not in a member of std"
- "Unable to start debugging. No process is associated with this object." - 在Visual Studio Code中使用GDB
- Where is std::hardware_destructive_interference_size?
- 将成员函数作为构造函数参数调用时出错 "Variable is not a type name"
- What is unordered_set in C++
- 你如何理解"std: :forward is just syntactic sugar"?这是真的吗?
- C++ "error: use of overloaded operator '*' is ambiguous"似乎只有一场比赛
- C++ is calculating wrong
- Is it good to use SDL_PIXELFORMAT_UNKNOWN?
- reference_wrapper导致"incomplete type is not allowed"
- 为什么即使在定义之后仍存在"Identifier is undefined error "?
- 结构中的错误"Incomplete type is not allowed"
- Crash in boost::archive::text_iarchive in_archive {is} boost
- 为什么这段代码会出现"exception spec is more lax than base"错误?