При объявлении переменных в области видимости {} они все равно будут использовать память после? - PullRequest
8 голосов
/ 13 января 2011

в этом примере, хотя я никогда не буду использовать переменные 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;
    }

Но ямне интересно, если бы я поместил их в область, они все еще будут использовать память во время цикла сообщений?например,

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);

, это помешало бы им использовать память?

Ответы [ 9 ]

6 голосов
/ 13 января 2011

У компилятора есть много возможностей для работы с простыми локальными файлами, как у вас в примерах. Они могут жить в стеке, они могут существовать только как непосредственные значения в машинном коде, или они могут просто жить в регистрах. Пространство стека обычно выделяется при входе в функцию. Компилятор вычтет некоторое значение из указателя стека, чтобы освободить место для всех локальных объектов. При возврате функции указатель стека восстанавливается до своего первоначального значения. Обычно это не делается при выходе из разных блоков области видимости. Большинство компиляторов пытаются агрессивно повторно использовать пространство стека, как только переменные больше не используются. В вашем примере было бы совершенно законно, чтобы x и msg имели одинаковый адрес в стеке, поскольку их использование не перекрывается.

Мой ответ на на этот вопрос более подробно описывает, как локальные переменные размещаются в стеке.

В ваших примерах константы, cx и cy, скорее всего, не будут иметь памяти, поддерживающей их во время выполнения, а будут просто непосредственными значениями в сгенерированном коде. x и y, скорее всего, будут жить в регистрах, пока их не нужно будет поместить в стек для вызова CreateWindow. wc и msg почти наверняка будут в стеке.

Вы не должны беспокоиться о микрооптимизации на этом уровне - пусть компилятор выделяет пространство для локальных переменных так, как считает нужным. По умолчанию у вас есть стек 1 МБ, объем данных, потребляемых этими переменными, даже не будет регистрироваться как шум. Вместо этого тратьте время на беспокойство о более интересных проблемах.

3 голосов
/ 13 января 2011

Вероятно, нет, но это деталь реализации. Они будут уничтожены, хотя (вызовы деструктора будут сделаны, если есть какие-либо, чтобы сделать) Время восстановления системы, используемой для автоматического хранения, не указано в стандарте. Большинство из них сразу же возвращают его назад.

1 голос
/ 13 января 2011

Один волшебный совет: Доверяйте своему компилятору. Он оптимизирует. Это умно. Он оптимизирует лучше, чем большинство из нас.

Если вы не уверены, используйте профилировщик или проверьте выходные данные компилятора после оптимизации. Но помните - тривиальные оптимизации - это то, что вы должны не делать в своем коде, поскольку это бессмысленно и только ухудшает читабельность вашего кода.

Некоторые переменные (особенно константы) не будут использовать любую память в стеке, потому что они будут либо отображены в регистры ЦП, либо встроены непосредственно в инструкцию ассемблера.

Это означает, что коды:

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);

будет компилироваться точно так же (если переменные больше никогда не используются).

Серьезно, не беспокойся. Если вы хотите оптимизировать, оптимизируйте с алгоритмической точки зрения, а не с синтаксической.

1 голос
/ 13 января 2011

Ну, я не уверен, что они используют память или что стандарт говорит об этом.

Что я знаю, так это то, что в конце блока памяти {} будет вызван деструктор, а переменные будут недоступны. Это может означать, что, хотя он не освобожден, по крайней мере, его можно использовать повторно.

Пример:

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

Редактировать: Спасибо, Томалак Герет'кал;)

0 голосов
/ 13 января 2011

Как правило, да, если переменная вообще находится в стеке, то место для нее будет занято в стеке в течение всей продолжительности включающей функции. Компиляторы обычно рассчитывают максимальный объем пространства, которое могут занимать переменные функции, а затем заставляют функцию выделять все это сразу при первом входе в функцию. Тем не менее, конструкторы и деструкторы будут по-прежнему вызываться при входе и выходе из внутренних областей. Пространство для переменных в одной области может использоваться повторно для представления переменных из отдельной области.

0 голосов
/ 13 января 2011

Если вы поместите их во вложенную область действия внутри функции (ваш первый вариант), то когда элемент управления достигнет конца области действия, переменные станут недоступными (либо ошибка компиляции, если вы используете их напрямую, либо неопределенное поведение во время выполнения, если Вы сохраняете указатель на один из них), их деструкторы запускаются (если есть деструкторы), и реализация может повторно использовать свое пространство хранения в кадре стека. Но стандарты не требуют его повторного использования.

Если вы разделите свою функцию на две части (ваш второй вариант) ... с точки зрения стандартной укладки, то нет никакой разницы! Когда функция возвращается, переменные становятся недоступными, их деструкторы запускаются, и реализация может повторно использовать свое пространство хранения, но это не требуется. И имели серьезные реализации - хотя и не C / C ++ - которые не сразу перезаписывают эту память: см. Наиболее известную статью " Чейни на M.T.A. "

Тем не менее, все реализации C / C ++ , о которых мне известно в настоящее время do , перезаписывают память, выделенную для локальных переменных функции, когда функция возвращается. Переработка памяти для переменных вложенной локальной области гораздо менее надежна. В любом случае, как упоминали несколько других людей, не стоит беспокоиться о нескольких десятках байтов стекового пространства в этом контексте.

Лично я бы разбил ваш код на две функции только потому, что таким образом каждая функция выполняет только одну задачу. Это обычно лучше для долгосрочного обслуживания.

0 голосов
/ 13 января 2011

Они не будут.Они будут жить только до конца блока.

0 голосов
/ 13 января 2011

Ваши объявленные переменные внутри {} будут выходить за рамки и будут потеряны. Фактически, вы получите ошибку компиляции, если попытаетесь использовать их вне блока: 'x' не объявлено. Однако это небрежно. Просто сделайте функцию для этого кода, как вы сказали в своем редактировании. Удерживать в main () как можно меньше строк - это хорошая практика программирования.

0 голосов
/ 13 января 2011

О боже, четыре целых числа в памяти во время работы программы, что за пустая трата!

  1. Попробуйте, достаточно простого ящика сообщений, который пытается их напечатать (я думаю).
  2. Даже не против.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...