未在递归函数中创建调用堆栈

Callstack not created in recursive function

#include<iostream>
#include<vector>
#include<stack>
#include<utility>
#define P(i, j) all[i-r0][j-c0]
#define C(i, j) check[i-r0][j-c0]

int r0, c0, r1, c1;
std::stack<std::pair<std::pair<int, int>, int>> s;
std::vector<int> mov = {-1, 0, 1};

int move(std::vector<std::vector<bool>> all, std::vector<std::vector<bool>> check){
    auto p = s.top();
    if(p.first.first==r1&&p.first.second==c1)
        return p.second;
    while(!s.empty()){
        for(int i=0; i<3; i++)
            for(int j=0; j<3; j++){
                auto r = p;
                r.first.first += mov[i];
                r.first.second += mov[j];
                r.second++;
                if(r.first.first>=r0&&r.first.first<=r1&&r.first.second>=c0&&r.first.second<=c1&&P(r.first.first, r.first.second)&&!C(r.first.first, r.first.second)){
                    s.push(r);
                    C(r.first.first, r.first.second) = 1;
                    return move(all, check);
                }
            }
        s.pop();
    }
}

int main(){
    std::cin>>r0>>c0>>r1>>c1;
    s.push({{r0, c0}, 0});
    int n;  std::cin>>n;
    std::vector<std::vector<bool>> all(r1-r0+1, std::vector<bool>(c1-c0+1));
    std::vector<std::vector<bool>> check(r1-r0+1, std::vector<bool>(c1-c0+1));
    C(r0, c0)=1;
    for(int i=0; i<n; i++){
        int tempx;
        std::cin>>tempx;
        int tempy1, tempy2;
        std::cin>>tempy1>>tempy2;
        for(int j=tempy1; j<=tempy2; j++)
            if(j<=c1&&j>=c0&&tempx<=r1&&tempx>=r0)
                P(tempx, j) = 1;
    }
    std::cout<<move(all, check)<<'\n';
}

在上面的程序中,当我提供以下输入时

5 7 6 11
3
5 3 8
6 7 11
5 2 5

然后使用调试器分析代码,奇怪的是在第 6 次调用时,当代码到达 return move(all, check) 时,它没有被调用,也没有为它创建堆栈。相反,它只是被跳过并且 s.pop() 函数被顺序调用。这有什么正当理由吗?

如果您将它放在调试器上,请在 return move(all, check)s.pop() 处使用断点。

Is there any valid reason for this ?

是的,这些原因是编译器优化,特别是tail call optimization。只要程序的可观察行为不变,编译器就可以生成他们想要的任何代码。

在这种情况下,尾调用优化允许编译器通过重用当前堆栈帧来消除创建新堆栈帧的开销。由于您的调试会话(和堆栈帧)不被视为可观察行为的一部分,因此编译器完全有权像这样弄乱调用堆栈。

内联函数也会发生类似的事情:您也不会获得新的堆栈帧,因为函数调用已被内联代码替换。

不过大多数编译器不会在调试版本中进行这些优化。因此,如果您更喜欢使用 "real" 调用堆栈进行调试,请切换到调试版本(并希望错误仍然出现在那里)。