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)即使到达下一次迭代时也不在范围之外?
答案 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::vector
或std::ifstream
,那么这些大括号是非常必要的。