开发者

When declaring variables in {} scope, will they still use memory after?

开发者 https://www.devze.com 2023-02-03 18:51 出处:网络
in this example, even though i will never use the variables WNDCLASSEX, x, y, cx, cy, they will still use memory when i\'m in the message loop:

in this example, even though i will never use the variables WNDCLASSEX, x, y, cx, cy, they will still use memory when i'm in the message loop:

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 = (GetSystemMetri开发者_JS百科cs(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;
    }

But i'm wondering, if i put them in a scope, would they still use memory during the message loop? 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;
}

or maybe if i put them into two functions and called them in winmain e.g.

wnd_register(hInst);
wnd_create(hInst);

would that prevent them from using the memory?


The compiler has a lot of leeway for handling simple locals, like you have in your examples. They may live on the stack, they may only exist as immediate values in the machine code, or they may just live in registers. Stack space is usually allocated on entry to a function. The compiler will subtract some value from the stack pointer to make space for all the locals. On return of the function, the stack pointer is restored back to its original value. This is not usually done on exit of different scope blocks. Most compilers will try to aggressively reuse stack space as soon as variables are no longer used. In your example, it'd be perfectly legal for x and msg to have the exact same address on the stack, since their usage is non-overlapped.

My answer to this question goes into more detail on how local variables are allocated on the stack.

In your examples, the constants, cx and cy, most likely will have no memory backing them at runtime, and just be immediate values in the generated code. x and y will most likely live in registers until they need to be pushed on the stack for the call to CreateWindow. wc and msg will almost definitely be on the stack.

You shouldn't worry about micro-optimizations at this level - let the compiler allocate space for local variables as it sees fit. You have a 1 MB stack by default, the amount of data consumed by these variables wouldn't even register as noise. Spend your time worrying about more interesting problems instead.


Probably not, but that's an implementation detail. They will have been destroyed though (destructor calls will have been made if there are any to make). Whether and when the system recovers memory used for automatic storage is not specified by the standard. Most do give it back pretty much immediately afaik.


One magic piece of advice: Trust your compiler. It optimizes. It is clever. It optimizes better than most of us could.

If you're unsure, use a profiler or examine the assembler output of the compiler after optimizations. But remember - trivial optimizations is something you should not do in your code, as it's pointless and only hurts your code's readability.

Some variables (especially the constants) will not use any memory on the stack because they will be either mapped onto CPU registers or embedded directly into an assembler instruction.

This implies that the codes:

func(123+456*198*value);

and

int a = 123;
int b = 56;
int c = 400;
int d = b+c;
int e = d*198;
e *= value;
e += a;
func(e);

would compile to exactly the same thing (if the variables are never used again).

Seriously, don't bother. If you want to optimize, optimize from the algorithmic point of view, not syntaxical.


Well, I'm not sure about them using memory or what the standard say about it.

What I do know is that at the end of a memory block { } the destructor will be called and variables will be unreachable. This could mean that, while it's not freed, at least it can be reused.

Example:

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.
}

Edit: Thanks Tomalak Geret'kal ;)


Oh god no, four integers in the memory while the program is running, what a waste!

  1. Try it out, a simple messagebox trying to print them should suffice (I think).
  2. Don't even mind.


Your declared variables inside the {}'s will go out of scope and be lost. In fact, you'll get a compile error if you try to use them outside the block: 'x' is undeclared. However, this it is sloppy. Just make a function for this code, as you said in your edit. Keeping your main() as few lines as possible is plain good programming practice.


They will not. They will only live until the end of their enclosing block.


If you put them in a nested scope within the function (your first option), then when control reaches the end of the scope, the variables become inaccessible (either a compile error if you use them directly, or runtime undefined behavior if you save a pointer to one of them), their destructors are run (if there are destructors), and the implementation may reuse their storage space within the stack frame. But the standards do not require it to reuse the space.

If you split your function in two (your second option) ... in terms of standard-hairsplitting, there is no difference! When the function returns, the variables become inaccessible, their destructors are run, and the implementation may reuse their storage space, but it is not required to. And there have been serious implementations -- albeit not of C/C++ -- that do not immediately recycle that memory: see most famously the paper "Cheney on the M.T.A."

However, all implementations of C/C++ that I am presently aware of do recycle the memory allocated for a function's local variables when a function returns. Recycling of memory for nested-local-scope variables is much less certain. In any event, as several other people have mentioned, it is not worth worrying about a few tens of bytes of stack space in this context.

Personally, I would break up your code into two functions just because that way each function does only one task. That's generally better for long-term maintenance.


Generally yes, if the variable resides on the stack at all, then space for it will be taken on the stack for the entire duration of the enclosing function. Compilers usually calculate the maximum amount of space the function's variables could occupy and then make the function allocate all of it at once when the function is first entered. Constructors and destructors will still get called upon entry and exit of the inner scopes, though. Space for variables in one scope may get reused to represent variables from a separate scope.

0

精彩评论

暂无评论...
验证码 换一张
取 消