哪个递归函数会花费更少的内存?

时间:2018-04-10 16:26:51

标签: c++ recursion

void func(int depth){
    if(depth== 0) return;
    int number(12345);
    cout << number; //it does something with number
    func(--depth);
}
void func2(int depth){
    if(depth== 0) return;
    {
        int number(12345);
        cout << number; //it does something with number
    }
    func2(--depth);
}
void main(){
    func(10); //will this function cost more memory?
    func2(10);//will this function cost less memory?
}

您好。我这里有两个功能。 func2会花费更少的内存,因为它的数字(12345)被“{}”封装,所以当func2调用下一次迭代时,数字(12345)可以超出范围并消失吗?

我相信func会花费更多,因为它的数量(12345)即使到达下一次迭代时也不在范围之外?

3 个答案:

答案 0 :(得分:6)

假设我们有AMD / Intel x86_64架构,而我们的编译器是GCC。

让我们获取装配输出(-O2 -S)并分析:

func:
.LFB1560:
    pushq   %rsi
    .seh_pushreg    %rsi
    pushq   %rbx
    .seh_pushreg    %rbx
    subq    $40, %rsp
    .seh_stackalloc 40
    .seh_endprologue
    movl    %ecx, %ebx
    testl   %ecx, %ecx
    je  .L3
    movq    .refptr._ZSt4cout(%rip), %rsi
    .p2align 4,,10
.L5:
    movl    $12345, %edx
    movq    %rsi, %rcx
    call    _ZNSolsEi
    subl    $1, %ebx
    jne .L5
.L3:
    addq    $40, %rsp
    popq    %rbx
    popq    %rsi
    ret
    .seh_endproc

func2:
.LFB2046:
    pushq   %rsi
    .seh_pushreg    %rsi
    pushq   %rbx
    .seh_pushreg    %rbx
    subq    $40, %rsp
    .seh_stackalloc 40
    .seh_endprologue
    movl    %ecx, %ebx
    testl   %ecx, %ecx
    je  .L10
    movq    .refptr._ZSt4cout(%rip), %rsi
    .p2align 4,,10
.L12:
    movl    $12345, %edx
    movq    %rsi, %rcx
    call    _ZNSolsEi
    subl    $1, %ebx
    jne .L12
.L10:
    addq    $40, %rsp
    popq    %rbx
    popq    %rsi
    ret
    .seh_endproc

正如您所看到的,两个功能完全相同。

答案 1 :(得分:0)

为什么推测?

由于你的深度很小(即10很小),你应该运行你的MCVE。

只需进行两项小改动即可确定您的答案:

a)cout数字的地址(除了值)。

b)取代const数,取一些不常数的东西。 (见下文)

#include <iostream>
#include <iomanip>


class T595_t
{

public:

   T595_t() = default;
   ~T595_t() = default;

   int exec(int , char**)
      {
         std::cout << "\n  func1(10)" << std::flush;
         func1(10);

         std::cout << "\n  func2(10)" << std::flush;
         func2(10);


         return 0;
      }

private: // methods

   void func1(int depth)
      {
         if(depth== 0) return;
         uint64_t number(time(nullptr));
         std::cout << "\n  " << depth 
                   << " " << number << "  " << &number;
         func1(--depth);
      }

   void func2(int depth)
      {
         if(depth== 0) return;
         {
            uint64_t number(std::time(nullptr));
            std::cout << "\n  " << depth 
                      << " " << number << "  " << &number;
         }
         func2(--depth);
      }

}; // class T595_t


int main(int argc, char* argv[])
{
   T595_t  t595;
   return  t595.exec(argc, argv);
}

使用输出(在Ubuntu 17.10上,使用g ++版本7.2.0。)

  func1(10)
  10 1523379410  0x7ffd449d7d90
  9 1523379410  0x7ffd449d7d60
  8 1523379410  0x7ffd449d7d30
  7 1523379410  0x7ffd449d7d00
  6 1523379410  0x7ffd449d7cd0
  5 1523379410  0x7ffd449d7ca0
  4 1523379410  0x7ffd449d7c70
  3 1523379410  0x7ffd449d7c40
  2 1523379410  0x7ffd449d7c10
  1 1523379410  0x7ffd449d7be0
  func2(10)
  10 1523379410  0x7ffd449d7d90
  9 1523379410  0x7ffd449d7d60
  8 1523379410  0x7ffd449d7d30
  7 1523379410  0x7ffd449d7d00
  6 1523379410  0x7ffd449d7cd0
  5 1523379410  0x7ffd449d7ca0
  4 1523379410  0x7ffd449d7c70
  3 1523379410  0x7ffd449d7c40
  2 1523379410  0x7ffd449d7c10
  1 1523379410  0x7ffd449d7be0

当未经优化时,每个funcX的代码gen似乎都做同样的事情。并且由于代码在不到一秒的时间内完成,所有值(数字)都是相同的。

答案 2 :(得分:0)

嗯,带有-O0的GCC 6.2.1会为您的两个函数生成相同的程序集。

在单个函数中,关闭括号的作用是确定何时调用析构函数。例如,请考虑以下事项:

struct Number {
  int n;
  ~Number() { std::cout << "~" << n << ", "; }
};

void func(int depth){
    if(depth== 0) return;
    Number number{depth};
    std::cout << number.n << ", ";
    func(--depth);
}
void func2(int depth){
    if(depth== 0) return;
    {
      Number number{depth};
      std::cout << number.n << ", ";
    }
    func2(--depth);
}

int main(int, char**) {
  std::cout << "Calling func. \n";
  func(10);
  std::cout << "\n\n";
  std::cout << "Calling func1. \n";
  func2(10);
}

此输出

Calling func.
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, ~1, ~2, ~3, ~4, ~5, ~6, ~7, ~8, ~9, ~10,

Calling func1.
10, ~10, 9, ~9, 8, ~8, 7, ~7, 6, ~6, 5, ~5, 4, ~4, 3, ~3, 2, ~2, 1, ~1,

因此,如果number是某些std::vectorstd::ifstream,那么这些大括号是非常必要的。