Разница между строкой + = s1 и строкой = строка + s1

Одна из моих программ превышает ограничение по времени, когда я использую fans = fans + s[i], а когда я использую fans += s[i] это принимается... Почему это происходит? Чтобы объяснить больше, fan - это строка, а s - это тоже строка, поэтому при переборе по строке s я хочу только несколько символов s, поэтому я создаю новую строку fan. Теперь есть два способа добавить символ в мою новую строку фанаты. Проблема упоминается ниже

fans = fans + s[i]; // gives Time limit exceeded 
fans += s[i];       // runs successfully

Ответ 1

Для встроенных типов a += b в точности совпадает с a = a + b, но для классов эти операторы перегружены и вызывают разные функции.
В вашем примере fans = fans + s[i] создает временную строку и назначает (перемещает) ее fans, но fans += s[i] не создает эту временную строку, поэтому она может быть быстрее.

Ответ 2

std::string есть члены operator + и operator +=. Первый обычно реализуется с последним в качестве промежуточного временного. Выглядит примерно так (проверьте источник реализации, если хотите точно знать, что делает ваш):

/// note reference return type
std::string& operator +=(char c) 
{
    this->append(c);
    return *this;
}

// note value return type
std::string operator +(char c) const
{
    std::string tmp = *this;
    tmp += c; // or just tmp.append(c) directly
    return tmp;
}

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

Ответ 3

Если вы используете fans=fans+s[i], строка будет копироваться при каждом проходе цикла. Новый элемент будет добавлен в копию строки, а результат будет переназначен переменной fans. После этого старая строка должна быть удалена, потому что на нее больше нет ссылок. Это занимает много времени.

Если вы используете расширенное присваивание fans+=s[i] строка не будет копироваться при каждом проходе цикла, и нет необходимости удалять ссылочную переменную, поскольку здесь нет ссылочной переменной. Это экономит много времени.

Я надеюсь, теперь вы можете понять!

Ответ 5

Для фундаментальных типов a = a + b и a += b означают одно и то же.

Для произвольных типов классов a = a + b и a += b не связаны; они ищут разных операторов, и эти операторы могут делать произвольные вещи. То, что они на самом деле не связаны, - это запах кода, признак проблемы дизайна.

a = a + b становится operator=( a, operator+( a, b ) ) примерно; фактические правила поиска немного сложнее (включая операторы-члены и операторы, не являющиеся членами, и тот факт, что = не имеет оператора, не являющегося членом, и т.д.), но это является его ядром.

a += b становится operator+=( a, b ) в аналогичном смысле.

Теперь это общий шаблон для реализации + в терминах +=; если вы сделаете это, вы получите:

a = a + b

становится

a = ((auto)(a) += b);

где (auto) - это новая функция "создать временную копию аргумента" /.

По сути, a+=b может повторно использовать содержимое a напрямую, тогда как a = a + b не может; в настоящий момент a+b оценивается, он не знает, что a скоро будет перезаписано.

Некоторые библиотеки имеют дело с этим, используя технику, известную как "шаблоны выражений"; a+b - это не значение, а описание во время компиляции выражения a+b, которое при присвоении a фактически используется для заполнения a данными. С помощью шаблонов выражений a+=b фундаментальная проблема, a+=b в том, что a+=b зная больше, чем a=a+b.

Теперь, в частности, для std::string, a+b создает объект временной строки, затем a=(a+b) перемещает его в a (он может повторно использовать буфер объекта временной строки или буфер a, стандарт молчит в этом вопросе).

a+=b должны повторно использовать любой избыток мощности в a буфера. Так что если вы a.reserve(1<<30) (1 млрд), a+=b не может выделить больше.