简体   繁体   English

在std :: function中调用递归函数

[英]Call recursive function in std::function

I just wrote a thread pool using C++11/14 std::thread objects and use tasks in the worker queue. 我只是使用C ++ 11/14 std :: thread对象编写了一个线程池,并在worker队列中使用了任务。 I encountered some weird behaviour when calling recursive functions in lambda expressions. 在lambda表达式中调用递归函数时,我遇到了一些奇怪的行为。 The following code crashes if you implement fac() in a recursive fashion (both with clang 3.5 and gcc 4.9): 如果您以递归方式(同时使用clang 3.5和gcc 4.9)实现fac() ,则以下代码会崩溃:

#include <functional>
#include <vector>

std::size_t fac(std::size_t x) {
    // This will crash (segfault).
    // if (x == 1) return 1;
    // else return fac(x-1)*x;

    // This, however, works fine.
    auto res = 1;
    for (auto i = 2; i < x; ++i) {
        res *= x;
    }

    return res;
}

int main() {
    std::vector<std::function<void()> > functions;

    for (auto i = 0; i < 10; ++i) {
        functions.emplace_back([i]() {  fac(i); });
    }

    for (auto& fn : functions) {
        fn();
    }

    return 0;
}

It does, however, work fine with the iterative version above. 但是,它确实可以与上述迭代版本配合使用。 What am I missing? 我想念什么?

for (auto i = 0; i < 10; ++i) {
    functions.emplace_back([i]() {  fac(i); });

The first time through that loop, i is going to be set to zero, so you're executing: 一次通过该循环, i将被设置为零,因此您正在执行:

fac(0);

Doing so with the recursive definition: 使用递归定义来执行此操作:

if (x == 1) return 1;
else return fac(x-1)*x;

means that the else block will execute, and hence x will wrap around to whatever the maximum size_t value is (as it's unsigned). 表示将执行else块,因此x将回绕到size_t的最大值(因为它是无符号的)。

Then it's going to run from there down to 1 , consuming one stack frame each time. 然后它将从那里向下运行到1 ,每次消耗一个堆栈帧。 At a minimum, that's going to consume 65,000 or so stack frames (based on the minimum allowed value of size_t from the standards), but probably more, much more. 至少,那将消耗65000左右栈帧(根据允许的最小值size_t从标准),但可能更多, 更多

That's what causing your crash. 这就是导致您崩溃的原因。 The fix is relatively simple. 解决方法相对简单。 Since 0! 0! is defined as 1 , you can simply change your statement to be: 被定义为1 ,您可以简单地将语句更改为:

if (x <= 1)
    return 1;
return fac (x-1) * x;

But you should keep in mind that recursive functions are best suited to those cases where the solution space reduces quickly, a classic example being the binary search, where the solution space is halved every time you recur. 但是,请记住,递归函数最适合解决方案空间快速减少的情况经典的例子是二进制搜索,其中每次递归时解决方案空间减半。

Functions that don't reduce solution space quickly are usually prone to stack overflow problems (unless the optimiser can optimise away the recursion). 不能迅速减少解决方案空间的函数通常容易出现堆栈溢出问题(除非优化器可以优化递归)。 You may still run into problems if you pass in a big enough number and it's no real different to adding together two unsigned numbers with the bizarre (though I actually saw it put forward as a recursive example many moons ago): 如果传递的数字足够大,您可能仍然会遇到问题,并且将两个无符号的数字与奇异值相加并没有什么真正的区别(尽管我实际上看到它是许多月前作为递归示例提出的):

def addu (unsigned a, b):
    if b == 0:
        return a
    return addu (a + 1, b - 1)

So, in your case, I'd stick with the iterative solution, albeit making it bug-free: 因此,在您的情况下,我会坚持使用迭代解决方案,尽管使其没有错误:

auto res = 1;
for (auto i = 2; i <= x; ++i)   // include the limit with <=.
    res *= i;                   // multiply by i, not x.

Both definitions have different behavior for x=0 . 对于x=0两个定义都有不同的行为。 The loop will be fine as it uses the less-than operator: 循环将很好,因为它使用了小于运算符:

auto res = 1;
for (auto i = 2; i < x; ++i) {
    res *= x;
}

However, 然而,

if (x == 1) return 1;
else return fac(x-1)*x;

Results in a quasi-infinite loop as x == 1 is false and x-1 yields the largest possible value of std::size_t (typically 2 64 -1). x == 1为false且x-1产生std::size_t的最大可能值(通常为2 64 -1)时,将导致拟无限循环。

The recursive version does not take care of the case for x == 0 . 递归版本不考虑x == 0的情况。

You need: 你需要:

std::size_t fac(std::size_t x) {
    if (x == 1 || x == 0 ) return 1;
    return fac(x-1)*x;
}

or 要么

std::size_t fac(std::size_t x) {
    if (x == 0 ) return 1;
    return fac(x-1)*x;
}

没有匹配的 function 调用 'std::vector <std.. '< div><div id="text_translate"><p> 我正在解决的问题是:我必须采用<strong>T</strong>测试用例。 For each test case I have to take string as an input, then I need to arrange the input string as: <em>string at even position {double space} string at odd position</em> (example: <em>input</em> - StackOverflow, <em>output</em> - <strong>Sakvrlw</strong> <strong>tcOefo</strong> ). 我编写了以下代码,其中我为所有测试用例获取输入并将其存储在向量中。 然后我将 vector 的元素分配给另一个声明的 string s。</p><pre> #include &lt;cmath&gt; #include &lt;cstdio&gt; #include &lt;vector&gt; #include &lt;iostream&gt; #include &lt;algorithm&gt; #include &lt;string&gt; using namespace std; int main() { /* Enter your code here. Read input from STDIN. Print output to STDOUT */ int T,i; cout &lt;&lt; "Enter no. of test cases: "; cin &gt;&gt; T; vector&lt;string&gt; v; vector&lt;string&gt; odd; vector&lt;string&gt; even; string str; for(int i=0; i&lt;T; i++){ cin &gt;&gt; str; v.push_back(str); } string s; for(i=0; i&lt;v.size(); i++){ s = v.at(i); for(i=0; i&lt;s.size(); i++){ if(i==0){ even.push_back(s[i]); //*This is where I am getting error*. }else if(i==1){ odd.push_back(s[i]); }else{ if(i%2==0){ even.push_back(s[i]); }else{ odd.push_back(s[i]); } } } for(i=0; i&lt;even.size(); i++){ cout &lt;&lt; even.at(i); } cout &lt;&lt; " "; for(i=0; i&lt;odd.size(); i++){ cout &lt;&lt; odd.at(i); } cout &lt;&lt; endl; even.clear(); odd.clear(); s.clear(); } return 0; }</pre><p> 在编译上面的代码时,我得到"no matching error for call std::vector..." 。 <strong><em>我到底做错了什么?</em></strong></p></div></std..> - no matching function for call to 'std::vector<std.. '

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 递归 std::function 抛出错误 - Recursive std::function is throwing errors 递归 function 中的“没有匹配的 function 用于调用” - "no matching function for call" in recursive function std :: bad_function_call自调用递归lambda但没有提示 - std::bad_function_call of self-calling recursive lambda but no hints 在递归调用函数时堆栈溢出 - Stack overflow on recursive call of a function std :: async可以调用std :: function对象吗? - Can std::async call std::function objects? 没有匹配的 function 调用 'std::vector <std.. '< div><div id="text_translate"><p> 我正在解决的问题是:我必须采用<strong>T</strong>测试用例。 For each test case I have to take string as an input, then I need to arrange the input string as: <em>string at even position {double space} string at odd position</em> (example: <em>input</em> - StackOverflow, <em>output</em> - <strong>Sakvrlw</strong> <strong>tcOefo</strong> ). 我编写了以下代码,其中我为所有测试用例获取输入并将其存储在向量中。 然后我将 vector 的元素分配给另一个声明的 string s。</p><pre> #include &lt;cmath&gt; #include &lt;cstdio&gt; #include &lt;vector&gt; #include &lt;iostream&gt; #include &lt;algorithm&gt; #include &lt;string&gt; using namespace std; int main() { /* Enter your code here. Read input from STDIN. Print output to STDOUT */ int T,i; cout &lt;&lt; "Enter no. of test cases: "; cin &gt;&gt; T; vector&lt;string&gt; v; vector&lt;string&gt; odd; vector&lt;string&gt; even; string str; for(int i=0; i&lt;T; i++){ cin &gt;&gt; str; v.push_back(str); } string s; for(i=0; i&lt;v.size(); i++){ s = v.at(i); for(i=0; i&lt;s.size(); i++){ if(i==0){ even.push_back(s[i]); //*This is where I am getting error*. }else if(i==1){ odd.push_back(s[i]); }else{ if(i%2==0){ even.push_back(s[i]); }else{ odd.push_back(s[i]); } } } for(i=0; i&lt;even.size(); i++){ cout &lt;&lt; even.at(i); } cout &lt;&lt; " "; for(i=0; i&lt;odd.size(); i++){ cout &lt;&lt; odd.at(i); } cout &lt;&lt; endl; even.clear(); odd.clear(); s.clear(); } return 0; }</pre><p> 在编译上面的代码时,我得到"no matching error for call std::vector..." 。 <strong><em>我到底做错了什么?</em></strong></p></div></std..> - no matching function for call to 'std::vector<std.. ' 包装std :: thread调用函数 - Wrap std::thread call function 在函数调用中包装std :: cout - Wrapping std::cout in a function call std :: bind“呼叫没有匹配功能” - std::bind “no matching function for call” 在不同的线程中调用std :: function - Call std::function in different thread
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM