string += s1 和 string = string + s1 的区别

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

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

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

对于built-in类型 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 的设置很昂贵。整体功能可以(通常是)通过 move-assignment 语义到 caller-side 上的最终目的地变得更好,但是临时的开销是 none-the-less 还在那里。多做几次,你不会注意到有什么不同。执行数千次或数百万次等,这可能意味着 world 的差异。

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

如果你使用扩充赋值fans+=s[i],字符串将不会在每次循环中都被复制,并且不需要删除引用变量,因为这里没有引用变量。这样可以节省很多时间。

希望你现在明白了!!

对于基本类型,a = a + ba += b 意思相同。

对于任意class类型,a = a + ba += b是不相关的;他们查找不同的运算符,而这些运算符可以做任意事情。它们 实际上 无关的是代码异味,这是设计问题的标志。

a = a + b 大致变成了 operator=( a, operator+( a, b ) );实际查找规则有点复杂(涉及成员运算符和 non-member 运算符,以及 = 没有 non-member 运算符等事实),但这是核心

a += b 变成 operator+=( a, b ) 类似的意思。

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

a = a + b

变成

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

其中 (auto) 是新的 / "create a temporary copy of the argument" 功能。

从根本上说,a+=b可以直接复用a的内容,而a = a + b则不能;目前 a+b 正在评估,它不知道 a 将很快被覆盖。

一些图书馆使用一种称为 "expression templates" 的技术来处理这个问题; a+b 不是一个值,而是表达式 a+b 的 compile-time 描述,当分配给 a 时,它实际上用于用数据填充 a .使用表达式模板,消除了 a+=b 知道的比 a=a+b 多的根本问题。

现在,对于 std::stringa+b 创建一个临时字符串对象,然后 a=(a+b) 将其移动到 a(它可以重用临时字符串的缓冲区object or buffer of a, standard is silent on this matter).

a+=b 必须重新使用 a 缓冲区中的任何多余容量。所以如果你a.reserve(1<<30)(10亿),a+=b不能分配更多。