C++ 字符串之间的差异+;=s1和string=string+;s1

C++ 字符串之间的差异+;=s1和string=string+;s1,c++,performance,stdstring,compound-assignment,c++20,c++23,C++,Performance,Stdstring,Compound Assignment,C++20,C++23,当我使用fans=fans+s[I]时,我的一个程序超过了时间限制,而当我使用fans+=s[I]时,它被接受。。。为什么会发生这种情况? 为了进一步解释,fans是一个字符串,s也是一个字符串,所以在迭代字符串s时,我只需要s的一些字符,所以我创建了一个新的字符串fans。现在有两种方法可以将字符添加到我的新字符串fans中。问题如下所述 fans = fans + s[i]; // gives Time limit exceeded fans += s[i]; // runs

当我使用
fans=fans+s[I]
时,我的一个程序超过了时间限制,而当我使用
fans+=s[I]
时,它被接受。。。为什么会发生这种情况? 为了进一步解释,fans是一个字符串,s也是一个字符串,所以在迭代字符串s时,我只需要s的一些字符,所以我创建了一个新的字符串fans。现在有两种方法可以将字符添加到我的新字符串fans中。问题如下所述

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

对于内置类型
a+=b
a=a+b
完全相同(除了
a
只计算一次),但对于类,这些运算符重载并调用不同的函数。

在您的示例中,
fans=fans+s[i]
创建一个临时字符串,并将其分配(移动)到
fans
,但
fans+=s[i]
不会创建该临时字符串,因此可能会更快

std::string
具有成员
operator+
operator+=
。前者通常通过中间临时文件的方式与后者一起实施。实际上是这样的(如果您想确切了解自己的实现源代码,请检查您的实现源代码):


tmp
的设置非常昂贵。通过将分配语义移动到调用者端的最终目的地,总体功能可以(通常是)变得更好,但临时功能的开销仍然存在。这样做几次,你不会注意到区别。进行数千次或数百万次等操作,这可能意味着一个不同的世界。

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

如果使用增广赋值
fans+=s[i]
,则不会在每次循环过程中复制字符串,并且不需要删除引用变量,因为此处没有引用变量。这节省了很多时间


我希望现在你能理解

对于基本类型,
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);
其中
(自动)
是新的/“创建参数的临时副本”功能

基本上,
a+=b
可以直接重用
a
的内容,而
a=a+b
不能;在计算
a+b
时,它不知道
a
将很快被覆盖

一些库使用一种称为“表达式模板”的技术来处理这个问题
a+b
不是一个值,而是表达式
a+b
的编译时描述,当分配给
a
时,它实际上用于用数据填充
a
。有了表达式模板,就消除了
a+=b
了解比
a=a+b
更多的基本问题

现在,对于
std::string
来说,具体来说,
a+b
创建一个临时字符串对象,然后
a=(a+b)
将其移动到
a
(它可以重用临时字符串对象的缓冲区或
a
的缓冲区,标准对此没有说明)


a+=b
必须重用
a
缓冲区中的任何多余容量。因此,如果你
a.reserve(1一个是临时的,另一个不是。移动分配可以使前者更有效,但不能比后者更好。请提取并提供a,没有它,你的问题就离题了。作为新用户,也可以阅读。因此
fans
是一个std::string和
s[i]
是一个字符?还是另一个包含单个字符的字符串?@Naman你读过Ulrich Eckhardt和我的评论吗?至少你应该弄清楚
粉丝和
s[i]
是什么类型的,但实际上如果你把你的问题简化并添加一个完整的程序()我们可以复制和编译。只需检查提供给你的链接。这不会花费很长时间,而且会显著改进你的问题。谢谢!你不应该粘贴正在使用的程序的代码。你应该从代码中提取一个并发布。应该可以不更改就获取并编译它是的。它不应该包含任何不需要证明问题的内容。您的问题仍然缺少这些内容,因此它仍然是离题的。在另一个方面实现
string+anything
string+=anything
看起来总是效率低下(一个分配和解除分配太多)。您确定有这样的实现吗?@Deduplicator
+=
通常是这两种实现中效率最高的一种(尽管可能存在异常值)。通过如上所述调用
+=
来实现
+
是比较常见的,这不会产生任何显著的开销。两个运算符通常都通过常量引用接受其RHS参数(如果它是非常重要的),因此不需要额外复制该参数
a = ((auto)(a) += b);