【问题标题】:std::bad_function_call of self-calling recursive lambda but no hints自调用递归 lambda 的 std::bad_function_call 但没有提示
【发布时间】:2015-03-12 22:36:51
【问题描述】:

我在 OSX 上使用 lldb 和 llvm (clang 6.0)。 以下代码在第 30 行抛出一个 std::bad_function_call:

std::function<void ( const std::shared_ptr<Node>, unsigned int )> find_next;
find_next = [=]( const std::shared_ptr<Node> node_to, unsigned int len )
{
    for ( const auto rhs : _edges )
    {  
        assert(node_to);
        assert(rhs.from);
        if ( (*node_to) == (*rhs.from) ) 
        {
            len++;
            find_next ( rhs.from, len );   // line 30
        }
    }
};

这是调用者,就在 lambda 定义的正下方:

for ( const auto lhs : _edges )
{
    unsigned int len = 0;
    const auto from = lhs.to;
    find_next ( from, len );
}

这是 lldb 输出:

libc++abi.dylib: terminating with uncaught exception of type std::__1::bad_function_call: std::exception
Avg Path Length: Process 4369 stopped
* thread #1: tid = 0x17220, 0x00007fff8c2bd282 libsystem_kernel.dylib`__pthread_kill + 10, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    frame #0: 0x00007fff8c2bd282 libsystem_kernel.dylib`__pthread_kill + 10
libsystem_kernel.dylib`__pthread_kill + 10:
-> 0x7fff8c2bd282:  jae    0x7fff8c2bd28c            ; __pthread_kill + 20
   0x7fff8c2bd284:  movq   %rax, %rdi
   0x7fff8c2bd287:  jmp    0x7fff8c2b8ca3            ; cerror_nocancel
   0x7fff8c2bd28c:  retq  

运行回溯:

(lldb) bt
* thread #1: tid = 0x17220, 0x00007fff8c2bd282 libsystem_kernel.dylib`__pthread_kill + 10, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
  * frame #0: 0x00007fff8c2bd282 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00007fff8bca24c3 libsystem_pthread.dylib`pthread_kill + 90
    frame #2: 0x00007fff918ebb73 libsystem_c.dylib`abort + 129
    frame #3: 0x00007fff8ba8ea21 libc++abi.dylib`abort_message + 257
    frame #4: 0x00007fff8bab69b9 libc++abi.dylib`default_terminate_handler() + 243
    frame #5: 0x00007fff8c3f96db libobjc.A.dylib`_objc_terminate() + 124
    frame #6: 0x00007fff8bab40a1 libc++abi.dylib`std::__terminate(void (*)()) + 8
    frame #7: 0x00007fff8bab3b30 libc++abi.dylib`__cxa_throw + 121
    frame #8: 0x000000010009f453 extras`std::__1::function<void (this=0x0000000100400370, __arg=shared_ptr<cgpp::Node> at 0x00007fff5fbfec28, __arg=1)>::operator()(std::__1::shared_ptr<cgpp::Node>, unsigned int) const + 131 at functional:1753
    frame #9: 0x000000010009edfd extras`cgpp::ConceptualGraph::avgPathLength(this=0x0000000100400360, node_to=<unavailable>, len=1) const::$_0::operator()(std::__1::shared_ptr<cgpp::Node>, unsigned int) const + 925 at ConceptualGraphEXTRAS.cpp:30
    frame #10: 0x000000010009e992 extras`std::__1::__function::__func<cgpp::ConceptualGraph::avgPathLength() const::$_0, std::__1::allocator<cgpp::ConceptualGraph::avgPathLength() const::$_0>, void (std::__1::shared_ptr<cgpp::Node>, unsigned int)>::operator()(std::__1::shared_ptr<cgpp::Node>&&, unsigned int&&) [inlined] decltype(this=0x0000000100400360, __f=0x0000000100400360, __args=0x00007fff5fbfef50, __args=0x00007fff5fbfeeb4) const::$_0&>(fp)(std::__1::forward<std::__1::shared_ptr<cgpp::Node>, unsigned int>(fp0))) std::__1::__invoke<cgpp::ConceptualGraph::avgPathLength() const::$_0&, std::__1::shared_ptr<cgpp::Node>, unsigned int>(cgpp::ConceptualGraph::avgPathLength() const::$_0&&&, std::__1::shared_ptr<cgpp::Node>&&, unsigned int&&) + 119 at __functional_base:413
    frame #11: 0x000000010009e91b extras`std::__1::__function::__func<cgpp::ConceptualGraph::avgPathLength(this=0x0000000100400350, __arg=0x00007fff5fbfef50, __arg=0x00007fff5fbfeeb4) const::$_0, std::__1::allocator<cgpp::ConceptualGraph::avgPathLength() const::$_0>, void (std::__1::shared_ptr<cgpp::Node>, unsigned int)>::operator()(std::__1::shared_ptr<cgpp::Node>&&, unsigned int&&) + 91 at functional:1370
    frame #12: 0x000000010009f48d extras`std::__1::function<void (this=0x00007fff5fbff340, __arg=shared_ptr<cgpp::Node> at 0x00007fff5fbfef50, __arg=0)>::operator()(std::__1::shared_ptr<cgpp::Node>, unsigned int) const + 189 at functional:1755
    frame #13: 0x000000010009cc89 extras`cgpp::ConceptualGraph::avgPathLength(this=0x0000000100304e38) const + 1065 at ConceptualGraphEXTRAS.cpp:40
    frame #14: 0x00000001000029e6 extras`main + 3334 at extras.cpp:37
    frame #15: 0x00007fff869b15c9 libdyld.dylib`start + 1
    frame #16: 0x00007fff869b15c9 libdyld.dylib`start + 1

我按值捕获所有内容,因为如果我按引用捕获,迭代器似乎会使指针无效。

我不明白的是,第 30 行的递归调用,我从 lldb (frame #9: 0x000000010009edfd) 得到 node_to 不可用的提示.但是断言没有捕捉到这一点,而只是抛出了一个 std::bad_function_call ,如果我理解正确,这意味着我正在调用的函数是无效的?

编辑:我做了一个缩小的例子:on ideone.com

【问题讨论】:

  • 通过 const 引用获取节点不是更高效吗?这将阻止更新共享指针计数。
  • @NeilKirk 我猜会是这样,但它不能解决我的问题 :-)
  • 你有 C++14 吗?在你的平台上编译的auto f = [](auto x){return x;} std::cout &lt;&lt; f(3) &lt;&lt; '\n'怎么样?
  • 不,恐怕只有 C++11。你认为它的参数类型?因为 lldb 似乎暗示问题出在参数上,但它为函数调用抛出。

标签: c++ c++11 recursion lambda


【解决方案1】:

您在将 lambda 分配给它之前按值捕获 find_next,而它仍然是空的。

引用捕获应该可以工作,只要您不需要复制该功能并在销毁原始文件后使用它即可。

【讨论】:

  • 你能添加一个例子吗?如果我通过引用捕获,我会从 for 循环中获得范围限制错误 (EXC_BAD_ACCESS)。
  • @Alex:该示例只是将[=] 替换为[&amp;],或者[&amp;find_next],以确保您没有捕获任何您不期望的东西。我看不到任何会导致越界访问的东西;您需要调试代码,或发布enough code 以重现错误。
  • @Mike 可能有生命周期——如果你使用 &amp;find_next 的副本将无法使用,因此如果 Alex 将 find_next 传递到本地范围之外,它将中断。
  • @Alex simple printf 对您的示例进行的调试显示了清晰的无限递归。修复无限递归,[&amp;] 修复你的问题。
  • @Alex 不,你有无限递归。不是无限循环。无限递归会破坏您的堆栈,并在发生这种情况时导致未定义的行为:无限循环通常会使您的代码挂起。编写递归代码时,请确保您的调用终止,并确保它不会太深(堆栈通常只有几 MB)。
猜你喜欢
  • 2013-04-01
  • 1970-01-01
  • 2014-09-24
  • 2011-09-16
  • 2016-09-04
  • 2019-10-24
  • 1970-01-01
  • 2011-04-30
  • 2019-06-20
相关资源
最近更新 更多