Я читал "Язык программирования C ++" Страуструпа, где он говорит, что из двух способов добавить что-то к переменной
x = x + a;
и
x += a;
Он предпочитает, +=
потому что это, скорее всего, лучше реализовано. Думаю, он имеет в виду, что тоже быстрее работает.
Но так ли это на самом деле? Если это зависит от компилятора и прочего, как мне проверить?
c++
performance
operators
Chiffa
источник
источник
Ответы:
Любой достойный компилятор сгенерирует точно такую же последовательность на машинном языке для обеих конструкций для любого встроенного типа (
int
,float
и т. Д.), Если оператор действительно настолько простx = x + a;
и оптимизация включена . (Примечательно, что GCC-O0
, который является режимом по умолчанию, выполняет антиоптимизацию , например, вставляет в память совершенно ненужные хранилища, чтобы гарантировать, что отладчики всегда могут найти значения переменных.)Однако если утверждение более сложное, они могут быть другими. Предположим
f
, это функция, которая возвращает указатель, тогдазвонит
f
только один раз, тогда какназывает это дважды. Если
f
есть побочные эффекты, одно из двух будет неправильным (возможно, второе). Даже если уf
него нет побочных эффектов, компилятор не сможет устранить второй вызов, поэтому последний действительно может быть медленнее.И поскольку мы говорим здесь о C ++, ситуация совершенно иная для типов классов, которые перегружают
operator+
иoperator+=
. Еслиx
это такой тип, то - до оптимизации -x += a
преобразуется вx.operator+=(a);
тогда как
x = x + a
переводится какauto TEMP(x.operator+(a)); x.operator=(TEMP);
Теперь, если класс написан правильно и оптимизатор компилятора достаточно хорош, оба будут генерировать один и тот же машинный язык, но это не так точно, как для встроенных типов. Вероятно, это то, о чем думает Страуструп, когда поощряет использование
+=
.источник
expr
вvar
isvar+=expr
и написания ее другим способом запутает читателей.*f() = *f() + a;
, возможно, вам стоит хорошенько взглянуть на то, чего вы действительно пытаетесь достичь ...1
является константой,a
может быть изменчивым, определяемым пользователем типом или чем-то еще. Полностью отличается. На самом деле, я не понимаю, как это вообще закрылось.Вы можете проверить, посмотрев разборку, которая будет такой же.
Для основных типов оба одинаково быстры.
Это результат, сгенерированный отладочной сборкой (т.е. без оптимизации):
a += x; 010813BC mov eax,dword ptr [a] 010813BF add eax,dword ptr [x] 010813C2 mov dword ptr [a],eax a = a + x; 010813C5 mov eax,dword ptr [a] 010813C8 add eax,dword ptr [x] 010813CB mov dword ptr [a],eax
Для определяемых пользователем типов , где можно перегрузить
operator +
иoperator +=
, это зависит от их соответствующих реализаций.источник
a
равно 1 , иx
этоvolatile
компилятор может генерироватьinc DWORD PTR [x]
. Это медленно.operator +
ничего не делать иoperator +=
вычислить 100000-е простое число, а затем вернуться. Конечно, это было бы глупо, но это возможно.++x
иtemp = x + 1; x = temp;
, то, скорее всего, она должна быть написана на ассемблере, а не на C ++ ...Да! Быстрее писать, быстрее читать и быстрее понимать, последнее в том случае, если
x
может иметь побочные эффекты. Так что для людей это в целом быстрее. Человеческое время в целом стоит намного больше, чем компьютерное время, так что вы, должно быть, и спрашивали об этом. Правильно?источник
Это действительно зависит от типа x и a и реализации +. За
компилятор должен создать временный T, содержащий значение x + a, пока он оценивает его, который затем может присвоить x. (Во время этой операции нельзя использовать x или a в качестве рабочей области).
Для x + = a временное значение не требуется.
Для тривиальных типов разницы нет.
источник
Разница между
x = x + a
иx += a
заключается в объеме работы, которую должна выполнить машина - некоторые компиляторы могут (и обычно делают) оптимизировать ее, но обычно, если мы какое-то время игнорируем оптимизацию, происходит то, что в предыдущем фрагменте кода машина должна найти значение дляx
дважды, в то время как в последнем случае этот поиск должен выполняться только один раз.Однако, как я уже упоминал, сегодня большинство компиляторов достаточно умны, чтобы анализировать инструкцию и сокращать требуемые результирующие машинные инструкции.
PS: Первый ответ о переполнении стека!
источник
Как вы назвали этот C ++, из двух опубликованных вами утверждений невозможно узнать. Вам нужно знать, что такое «x» (это немного похоже на ответ «42»). Если
x
это POD, то особой разницы в этом нет. Однако, еслиx
это класс, может быть перегрузками дляoperator +
иoperator +=
методов , которые могут иметь различные модели поведения , которые приводят к очень разному времени исполнения.источник
Если вы говорите
+=
, что значительно упрощаете жизнь компилятору. Чтобы компилятор распознал, чтоx = x+a
это то же самоеx += a
, компилятор долженпроанализируйте левую часть (
x
), чтобы убедиться, что она не имеет побочных эффектов и всегда относится к одному и тому же l-значению. Например, это может бытьz[i]
, и он должен быть уверен, что и то,z
и другоеi
не изменится.проанализируйте правую часть (
x+a
) и убедитесь, что это суммирование, и что левая часть встречается один раз и только один раз в правой части, даже если она может быть преобразована, как вz[i] = a + *(z+2*0+i)
.Если вы имеете в виду добавить
a
что-тоx
, разработчик компилятора оценит это, когда вы просто говорите то, что имеете в виду. Таким образом, вы не тренируете ту часть компилятора, от которой, как надеется его автор, избавился от всех ошибок, и это на самом деле не облегчает вам жизнь, если только вы честно не можете вытащить голову режима Fortran.источник
В качестве конкретного примера представьте себе простой тип комплексного числа:
struct complex { double x, y; complex(double _x, double _y) : x(_x), y(_y) { } complex& operator +=(const complex& b) { x += b.x; y += b.y; return *this; } complex operator +(const complex& b) { complex result(x+b.x, y+b.y); return result; } /* trivial assignment operator */ }
Для случая a = a + b он должен создать дополнительную временную переменную, а затем скопировать ее.
источник
Вы задаете неправильный вопрос.
Это вряд ли повлияет на производительность приложения или функции. Даже если бы это было так, способ узнать это - профилировать код и точно знать, как он на вас влияет. Вместо того, чтобы беспокоиться на этом уровне о том, что быстрее, гораздо важнее думать с точки зрения ясности, правильности и удобочитаемости.
Это особенно верно, если учесть, что, даже если это значительный фактор производительности, компиляторы со временем развиваются. Кто-то может придумать новую оптимизацию, и правильный ответ сегодня может стать неправильным завтра. Это классический случай преждевременной оптимизации.
Это не значит, что производительность вообще не имеет значения ... Просто это неправильный подход к достижению ваших целей производительности. Правильный подход - использовать инструменты профилирования, чтобы узнать, где ваш код на самом деле проводит время и, следовательно, на чем сосредоточить свои усилия.
источник
Я думаю, это должно зависеть от машины и ее архитектуры. Если его архитектура допускает косвенную адресацию памяти, средство записи компилятора МОЖЕТ просто использовать вместо этого этот код (для оптимизации):
mov $[y],$ACC iadd $ACC, $[i] ; i += y. WHICH MIGHT ALSO STORE IT INTO "i"
Принимая во внимание, что
i = i + y
может быть переведено (без оптимизации):При этом
i
следует учитывать и другие сложности, например, если функция возвращает указатель и т. Д. Большинство компиляторов производственного уровня, включая GCC, создают один и тот же код для обоих операторов (если они целые).источник
Нет, оба варианта одинаковы.
источник