27

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

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

4 回答 4

28

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

于 2019-07-21T10:45:32.100 回答
12

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

于 2019-07-21T10:51:05.887 回答
11

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

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

我希望你现在能明白了!!

于 2019-07-21T11:00:16.077 回答
3

对于基本类型,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=a+b

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

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

于 2019-07-22T13:39:34.133 回答