Я читал некоторый исходный код C ++, и я подошел к некоторому синтаксису.
path& path::operator+=(string postPath)
и мне было интересно, является ли это фактическим синтаксисом и почему c ++ не использует уже существующий оператор + вместо этого в сочетании с применением значения к рассматриваемому объекту.
Это как, если вы хотите убедиться, что объект удаляется правильно. Но деструктор должен разобраться со всем этим.
-Edit1
Я знаю, что есть разница между a + = b; и А + В;
Мне было интересно, почему c ++ не просто использует оператор + с + = вместо того, чтобы переопределять оператор + = так же, как оператор +
-Edit2
Я не уверен, что все получилось правильно, но я спрашивал, почему язык не выводит + = на основе +.
И теперь я понимаю, другие применения + =. Спасибо всем 🙂
Там могут быть проблемы эффективности; если ваш объект дорогой для копирования / назначения, a+=b
потенциально спасает вас временную конструкцию, конструкцию копии и назначение, и позволяет вам лучше использовать ресурсы, которые у вас уже есть в целевом объекте. Если std::vector
был +=
Оператор конкатенации векторов, было бы гораздо эффективнее реализовать его напрямую (вы можете использовать дополнительную емкость целевого объекта и избежать бесполезного распределения) вместо создания временного вектора суммы (который начинается «с нуля») и его назначения.
На самом деле, обычно я реализую +
с точки зрения +=
обычно это дает код, который является одновременно более эффективным и простым для написания; как это:
T &operator+=(const T &r)
{
// say that T encapsulates an N-dimensional array
for(int i=0; i<N; ++i)
arr+=r.arr[i];
return *this;
}
T operator+(const T &r)
{
T ret(*this);
ret+=r;
return ret;
}
(хотя я согласен, что было бы неплохо иметь возможность попросить компилятор синтезировать +
/-
от существующих операторов; то же самое для реляционных операторов)
Вы можете захотеть иметь объект, который может быть добавлен, но не может быть скопирован / назначен. Например, для моего игрушечного проекта я кратко рассмотрел наличие перегруженных сигнальными объектами (например, boost или Qt, или .NET events / multicast делегаты), которые перегружены +=
добавить соединение (Signal &operator+=(std::function<T...> fn)
), но я не хотел иметь дело с семантикой назначения / копирования (что IMHO для сигнала не имеет смысла);
В основе всего этого лежит общая идея, что в C ++ вы можете перегружать (почти) все операторы, чтобы они делали что угодно, без особых ограничений семантики. Вы можете написать operator+
который запускает ракету и operator+=
это удаляет все файлы на вашем жестком диске — вы отвечаете, если в вашем приложении есть смысл, вы можете делать это без особых ограничений.
С ++ делает нет предположения относительно перегруженных операторов; вы можете
определить operator+
который не является коммутативным, например. а вы
может определить operator+=
который не имеет никакого отношения к operator+
,
Вы также можете определить operator+=
без определения operator+
или порок
наоборот.
Что касается того, почему: для начала, вы действительно не хотите, чтобы компилятор предполагал
тот operator+
на строки является коммутативным, и, следовательно, оптимизировать.
И однажды открыв дверь, авторы языка не сомневаются
чувствовал, что лучше оставить это на усмотрение программиста, а не
навязывать что-либо на уровне языка. Даже если я не могу придумать случай
могут быть случаи, когда имеет смысл поддержать +=
а также
+
с немного другой семантикой. Общая философия C ++
всегда должен был дать программисту все инструменты, которые ему необходимы для
писать хороший код, но не запрещать код, который не соответствует текущему
Идея о том, что плохой код. (В конечном итоге это окупилось, так как
наши идеи относительно того, что является хорошим и плохим кодом, развивались.)
Да, path& path::operator+=(string postPath);
действует и перегружает +=
оператор для случая, когда string
добавляется на path
,
Причина, по которой вы хотите иметь возможность перегрузки, проста: operator+
должен вернуть новое значение вместо того, чтобы изменить старое, в то время как operator+=
может повторно использовать существующий ресурс (например, выделенную память). Поскольку основной операцией добавления строк (то, что вы делаете) является выделение памяти, +=
может быть значительно более производительным в вашем конкретном случае.
Кроме того, операция SomePath + SomeString
ставит вопрос о SomeString + SomePath
и, что еще хуже, SomeStringA + SomePathB
, которые все немного отличаются, в то время как SomePath += SomeString
имеет очень четкое значение.
Так как теперь должно быть ясно, почему вы хочу быть в состоянии реализовать +=
без реализации +
рассмотрим другое направление: почему бы просто не использовать a = a + b
в качестве реализации по умолчанию для a += b
:
Во-первых, правила перегрузки операторов старше = delete
, Следовательно, это правило всегда триггер, даже в тех случаях, когда вы делаете не хочу operator+=
существовать вообще. Обратите внимание, что реализация «по умолчанию» очень проста:
A& operator+=(A const& other) { return *this = *this + other; }
почему C ++ не использует уже существующий оператор +, а в сочетании с применением значения
Именно потому что +=
мутирует и +
не делает. Это часто подразумевает значительные различия в реализации.
Внедрение a += b
как a = a+b
будет менее эффективным, чем его непосредственная реализация, поскольку ему придется создавать и уничтожать временный объект, назначенный a
,
Это более эффективно для реализации +
с точки зрения +=
path operator+(path prePath, string postPath) {
return prePath += postPath;
}
С философской точки зрения, можно утверждать, что менее удивительно, если язык магически не генерирует операторов, которых вы не ожидаете. Многие люди обнаруживаются неявно сгенерированными конструкторами и операторами присваивания, дающими своим типам неверную семантику копирования (пока они не изучат Правило трех), и другое магическое поведение может вызвать замешательство в других отношениях.