考虑这样的代码:
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
。
答案 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
。
对于strtemp
为str2
的情况,没有任何变化,因为在分配临时副本时,字符串会被放大,而不是之前。
即使标准中没有明确说明,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
,因此必须允许它。如果迭代器版本允许自我赋值,那么它也会非常奇怪,但指针和尺寸版本却没有。