Trying to compile the following code using the clang version in Xcode 6.1 (clang-600.0.54 based on LLVM 3.5svn), with -std=c++11
and -stdlib=libc++
gives me some errors that I don't really understand.
#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;
}
Results:
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.
Looks as if Impl::L::~L()
somehow inherits the noexcept(false)
of Hndl::~Hndl()
, but I don't know why.
Interestingly the same code compiles if I comment out the assignment to h.impl->i
inside the lambda.
Also compiles if I remove the noexcept(false)
specification from Hndl::~Hndl()
, but I need that (would be a bit long to explain why, but I do).
Also compiles if the lambda captures by ref, but the whole point here would be to be able to copy handles that share an implementation.
Adding noexcept(true)
to Impl::~Impl()
doesn't help.
ideone.com's c++11 compiler happily compiles it as it is.
Could anyone explain me what's happening here?
The lambda captures h
, which has a potentially-throwing destructor, so the lambda's closure type also has a potentially-throwing destructor.
With that in mind, you can reduce the problem to this:
#include <functional>
struct F
{
void operator()() { }
~F() noexcept(false) {}
};
int main() {
std::function<void ()> f = F{};
}
It seems that the std::function
in libc++ cannot store a callable type without a nothrow destructor which looks like a bug in libc++.
From the error messages it looks as though the fix might be as simple as adding an explicit noexcept
to the __func
destructor, but I'm not familiar with the implementation so it might not be that easy.
I don't see any obvious workarounds except wrapping your Hndl
type in another type with a noexcept
destructor, so capturing it in the lambda does not make the lambda have a noexcept(false)
destructor. I tried something like this, but libc++ seems to have similar problems in shared_ptr
:
std::function<void ()> f = std::bind(&Hndl::operator(), std::make_shared<Hndl>());
I think the problem is that Hndl
is captured in lambda by value and std::function
destructor is treated as noexcept(true)
since it is not stated otherwise in it's definition. So Hndl
instance cannot be safely destroyed in l
destructor. As for why error disappears if member assignment is removed from lambda - most likely captured value is just optimized away by compiler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With