字符串 += s1 和字符串 = 字符串 + s1 之间的区别

Difference between string += s1 and string = string + s1

本文关键字:字符串 s1 区别 之间      更新时间:2023-10-16

当我使用fans = fans + s[i]时,我的一个程序超过了时间限制,而当我使用fans += s[i]时,它被接受......为什么会这样? 为了解释更多,fans是一个字符串,s也是一个字符串,所以在迭代字符串s时,我只想要s的一些字符,所以我正在创建一个新的字符串风扇。现在有两种方法可以为我的新弦乐迷添加角色。下面提到了这个问题

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

> 对于内置类型a += ba = a + b完全相同(除了a只计算一次),但对于类,这些运算符被重载并调用不同的函数。
在您的示例中,fans = fans + s[i]创建一个临时字符串,并将其分配给(移动)fans,但fans += s[i]不会创建该临时字符串,因此它可能更快。

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的设置很昂贵。通过对调用方端最终目的地的移动赋值语义,整体功能可以(并且通常)变得更好,但临时的费用仍然存在。做几次,你不会注意到差异。做几千次,或者几百万次,等等,这可能意味着一个不同的世界

如果使用fans=fans+s[i],则字符串将在每次循环传递中复制。新元素将被添加到字符串的副本中,结果将被重新分配给变量fans。在此之后,必须删除旧字符串,因为它不再被引用。这需要很多时间。

如果使用增强赋值fans+=s[i]则不会在每次循环传递中复制字符串,并且无需删除引用变量,因为此处没有引用变量。这样可以节省大量时间。

希望现在你能明白!!

对于基本类型,a = a + ba += b的意思是一样的。

对于任意类类型,a = a + ba += b是不相关的;它们查找不同的运算符,这些运算符可以执行任意操作。 它们实际上是不相关的是代码气味,这是设计问题的标志。

a = a + b变得粗略operator=( a, operator+( a, b ) );实际的查找规则有点复杂(涉及成员运算符和非成员运算符,以及=没有非成员运算符的事实等),但这是它的核心。

a += b在类似的意义上变得operator+=( a, b )

现在,在+=方面实现+是一种常见的模式;如果你这样做,你会得到:

a = a + b

成为

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

其中(auto)是新的 C++20/C++23"创建参数的临时副本"功能。

从根本上说,a+=b可以直接重用a的内容,而a = a + b不能;在评估a+b的那一刻,它不知道a很快就会被覆盖。

一些库使用称为"表达式模板"的技术来处理此问题;a+b不是一个值,而是表达式a+b的编译时描述,当分配给a时,它实际上用于用数据填充a。 使用表达式模板,消除了a+=b知道的多于a=a+b的基本问题。

现在,具体来说std::stringa+b创建一个临时字符串对象,然后a=(a+b)将其移动到a中(它可以重用临时字符串对象的缓冲区或a的缓冲区,标准对此事保持沉默)。

a+=b必须重复使用a缓冲区中的任何多余容量。 因此,如果您a.reserve(1<<30)(10 亿),a+=b无法分配更多。