Эффективнее ли объявлять переменные поздно? - PullRequest
3 голосов
/ 18 октября 2011

Больше памяти или, возможно, вычислительно эффективно объявлять переменные поздно?

Пример:

int x;
code
..
.
.
. x is able to be used in all this code
.
actually used here
.
end

против

code
..
.
.
.
int x;
actually used here
.
end

Спасибо.

Ответы [ 4 ]

9 голосов
/ 18 октября 2011

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

Ваше время далеко более ценно, чем пытаться угадать взаимодействия компилятора и кэша на процессоре.


Например, для x86 эта программа:

#include <iostream>

int main() {
  for (int j = 0; j < 1000; ++j) {
    std::cout << j << std::endl;
  }
  int i = 999;
  std::cout << i << std::endl;
}

по сравнению с:

#include <iostream>

int main() {
  int i = 999;
  for (int j = 0; j < 1000; ++j) {
    std::cout << j << std::endl;
  }
  std::cout << i << std::endl;
}

скомпилировано с:

g++ -Wall -Wextra -O4 -S measure.c
g++ -Wall -Wextra -O4 -S measure2.c

Когдапроверка вывода с помощью diff measure*.s дает:

<       .file   "measure2.cc"
---
>       .file   "measure.cc"

Даже для:

#include <iostream>

namespace {
  struct foo {
    foo() { }
    ~foo() { }
  };
}

std::ostream& operator<<(std::ostream& out, const foo&) {
  return out << "foo";
}

int main() {
  for (int j = 0; j < 1000; ++j) {
    std::cout << j << std::endl;
  }
  foo i;
  std::cout << i << std::endl;
}

vs

#include <iostream>

namespace {
  struct foo {
    foo() { }
    ~foo() { }
  };
}

std::ostream& operator<<(std::ostream& out, const foo&) {
  return out << "foo";
}

int main() {
  foo i;
  for (int j = 0; j < 1000; ++j) {
    std::cout << j << std::endl;
  }
  std::cout << i << std::endl;
}

результаты diff сборки, произведеннойg++ -S все еще идентичны, за исключением имени файла, потому что нет никаких побочных эффектов.Если бы были побочные эффекты, то это указывало бы, где вы сконструировали объект - в какой момент вы хотели, чтобы побочные эффекты происходили?

5 голосов
/ 18 октября 2011

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

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

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

Так что, по сути, пишите так, как это логично, и вы, как правило, также получите самый эффективный код; или, по крайней мере, вы не сделаете ничего хуже, чем объявив все наверху.

5 голосов
/ 18 октября 2011

Для основных типов, таких как int, это не имеет значения с точки зрения производительности.Для типов class определение переменной также включает вызов конструктора, который может быть пропущен, если поток управления пропустит эту переменную.Кроме того, как для фундаментального, так и для class типов определение следует отложить по крайней мере до такой степени, чтобы было достаточно информации, чтобы сделать такую ​​переменную значимой.Для не типируемых типов классов по умолчанию это обязательно;для других типов это может не быть, но это заставляет вас работать с неинициализированными состояниями (например, -1 или другими недопустимыми значениями).Вы должны определить свои переменные как можно позже, в пределах минимально возможного объема;иногда это не имеет значения с точки зрения производительности, но всегда важно с точки зрения дизайна.

4 голосов
/ 18 октября 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...