将std :: string附加到自身是否安全?

时间:2016-05-06 14:25:36

标签: c++ stl

考虑这样的代码:

std::string str = "abcdef";
const size_t num = 50;

const size_t baselen = str.length();
while (str.length() < num)
    str.append(str, 0, baselen);

像这样呼叫std::basic_string<T>::append()本身是否安全?通过在复制操作之前放大,源内存是否无法生效?

我在该方法的标准中找不到任何内容。它说上面相当于str.append(str.data(), baselen),我认为可能不完全安全,除非在append(const char*, size_t)内再次检测到这种情况。

我检查了一些实现,他们看起来很安全,但我的问题是这种行为是否得到保证。例如。 &#34; Appending std::vector to itself, undefined behavior?&#34;说不是std::vector

2 个答案:

答案 0 :(得分:15)

根据§21.4.6.2/§21.4.6.3:

  

函数[ basic_string& append(const charT* s, size_type n); ]用长度为(+)+ n的字符串替换由* this控制的字符串,其第一个size()元素是原始字符串控制的副本by * this和其余元素是s的初始n个元素的副本。

注意:这适用于每个append调用,因为每个append都可以按照append(const charT*, size_type)实现,如标准所定义的那样(§21.4.6.2/§ 21.4.6.3)。

基本上,append制作了str的副本(让我们称之为副本strtemp),将n的{​​{1}}个字符追加到str2 },然后将strtemp替换为str

对于strtempstr2的情况,没有任何变化,因为在分配临时副本时,字符串会被放大,而不是之前。

即使标准中没有明确说明,str的定义也保证了(如果实施完全符合标准的规定)。

因此,这不是未定义的行为。

答案 1 :(得分:6)

这很复杂。

有一点可以肯定。如果使用迭代器:

std::string str = "abcdef";
str.append(str.begin(), str.end());

那么你保证是安全的。对真的。为什么?因为规范声明迭代器函数的行为等同于调用append(basic_string(first, last))。这显然会创建一个字符串的临时副本。因此,如果您需要在自身中插入一个字符串,那么您可以保证能够使用迭代器形式。

当然,实施不必实际复制它。但他们确实需要尊重标准的指定行为。只有当迭代器范围在其自身内部时,实现才可以选择复制,但实现仍然需要检查。

所有其他形式的append都定义为等同于调用append(const charT *s, size_t len)。也就是说,您上面追加的电话相当于您append(str.data(), str.size())。那么,如果s位于*this内,那么标准会说明会发生什么?

什么都没有。

s的唯一要求是:

  

s指向n个至少charT个元素的数组。

由于它明确地禁止s指向*this,因此必须允许它。如果迭代器版本允许自我赋值,那么它也会非常奇怪,但指针和尺寸版本却没有。