在这个例子中,即使我永远不会使用变量WNDCLASSEX,x,y,cx,cy,当我进入消息循环时,它们仍会使用内存:
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpArgs, int iCmdShow)
{
WNDCLASSEX wc;
...
RegisterClassEx(&wc);
const int cx = 640;
const int cy = 480;
// center of the screen
int x = (GetSystemMetrics(SM_CXSCREEN) - cx) / 2;
int y = (GetSystemMetrics(SM_CXSCREEN) - cy) / 2;
CreateWindow(..., x, y, cx, cy, ...);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
但是我想知道,如果我把它们放在一个范围内,它们是否仍会在消息循环中使用内存? e.g。
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpArgs, int iCmdShow)
{
{
WNDCLASSEX wc;
...
RegisterClassEx(&wc);
const int cx = 640;
const int cy = 480;
// center of the screen
int x = (GetSystemMetrics(SM_CXSCREEN) - cx) / 2;
int y = (GetSystemMetrics(SM_CXSCREEN) - cy) / 2;
CreateWindow(..., x, y, cx, cy, ...);
}
MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
或者如果我将它们分成两个函数并在winmain中调用它们,例如
wnd_register(hInst);
wnd_create(hInst);
会阻止他们使用内存吗?
答案 0 :(得分:6)
编译器在处理简单本地时有很大的余地,就像你在例子中一样。它们可能存在于堆栈中,它们可能仅作为机器代码中的直接值存在,或者它们可能只存在于寄存器中。堆栈空间通常在进入函数时分配。编译器将从堆栈指针中减去一些值,以便为所有本地生成空间。返回函数时,堆栈指针将恢复为原始值。这通常不会在退出不同范围块时完成。一旦不再使用变量,大多数编译器都会尝试积极地重用堆栈空间。在您的示例中,x和msg在堆栈上具有完全相同的地址是完全合法的,因为它们的使用是非重叠的。
我对this question的回答详细介绍了如何在堆栈上分配局部变量。
在您的示例中,常量cx和cy很可能在运行时没有内存支持它们,并且只是生成的代码中的立即值。 x和y很可能会存在于寄存器中,直到需要将它们压入堆栈以调用CreateWindow。 wc和msg几乎肯定会在堆栈中。
您不应该担心此级别的微优化 - 让编译器在其认为合适的情况下为局部变量分配空间。默认情况下,您有1 MB堆栈,这些变量消耗的数据量甚至不会记录为噪声。花时间担心更多有趣的问题。
答案 1 :(得分:3)
可能不是,但那是一个实现细节。它们虽然会被破坏(如果有任何东西可以进行析构函数调用)。系统是否以及何时恢复用于自动存储的内存未由标准指定。大多数人都会立即回复它。
答案 2 :(得分:1)
嗯,我不确定他们是否使用内存或标准对此有何看法。
我所知道的是,在内存块{}的末尾,将调用析构函数并且无法访问变量。这可能意味着,虽然它没有被释放,但至少它可以重复使用。
示例:
struct Foo {
Foo(void) { std::cout << "Hi!"; }
~Foo(void) { std::cout << "Bye!"; }
};
int main(int argc, char * argv[])
{
{
Foo bar; // <- Prints Hi!
} // <- Prints Bye!
// Memory used by bar is now available.
}
编辑:感谢Tomalak Geret'kal;)
答案 3 :(得分:1)
一条神奇的建议:信任您的编译器。它优化。这很聪明。它比我们大多数人更好地优化。
如果您不确定,请使用分析器或在优化后检查编译器的汇编器输出。但请记住 - 平凡的优化是你应该不在代码中做的事情,因为它没有意义,只会伤害你的代码的可读性。
某些变量(尤其是常量)不会在堆栈上使用任何内存,因为它们将映射到CPU寄存器或直接嵌入到汇编器指令中。
这意味着代码:
func(123+456*198*value);
和
int a = 123;
int b = 56;
int c = 400;
int d = b+c;
int e = d*198;
e *= value;
e += a;
func(e);
会编译成完全相同的东西(如果永远不再使用变量)。
说真的,不要打扰。如果你想优化,从算法的角度进行优化,而不是语法。
答案 4 :(得分:0)
哦,上帝不,程序运行时内存中有四个整数,真是浪费!
答案 5 :(得分:0)
{}中声明的变量将超出范围并丢失。事实上,如果你试图在块之外使用它们,你会得到编译错误:'x'是未声明的。但是,这很草率。只需为此代码创建一个函数,就像您在编辑中所说的那样。保持main()尽可能少的行是很好的编程习惯。
答案 6 :(得分:0)
他们不会。他们只会活到封闭的街区尽头。
答案 7 :(得分:0)
如果将它们放在函数中的嵌套作用域(第一个选项)中,那么当控件到达作用域的末尾时,变量将变得不可访问(如果直接使用它们则是编译错误,或者如果是运行时未定义的行为,则为保存指向其中一个的指针),运行它们的析构函数(如果有析构函数),并且实现可以重用堆栈帧中的存储空间。但是标准并没有要求它重用空间。
如果你将你的功能分成两部分(你的第二个选项)......就标准发型而言,没有区别!当函数返回时,变量变得不可访问,它们的析构函数被运行,并且实现可能重用它们的存储空间,但它不是必需的。并且已经已经认真实施 - 虽然不是C / C ++ - 但没有立即回收那些内存:最着名的是文章“Cheney on the M.T.A.”
但是,我目前所知道的的所有 C / C ++ 实现 在函数返回时回收为函数的局部变量分配的内存。为嵌套局部范围变量回收内存更不确定。无论如何,正如其他几个人所提到的,在这种情况下,不值得担心几十个字节的堆栈空间。
就个人而言,我会将你的代码分解成两个函数,因为每个函数只执行一个任务。这对于长期维护来说通常更好。
答案 8 :(得分:0)
通常是的,如果变量完全驻留在堆栈上,那么它的空间将在封闭函数的整个持续时间内被占用。编译器通常计算函数变量可能占用的最大空间量,然后在首次输入函数时使函数立即分配所有空间。但是,在内部作用域的进入和退出时,仍然会调用构造函数和析构函数。可以重用一个范围中变量的空间来表示来自单独范围的变量。