你能给自己分配一个 std::string 的子字符串吗?

Can you assign a substring of a std::string to itself?

本文关键字:string std 字符串 一个 自己 分配      更新时间:2023-10-16

我最近发现需要用自己的子字符串替换std::string的内容。我认为在这里调用的最合乎逻辑的函数如下,来自 http://www.cplusplus.com/reference/string/string/assign/:

substring (2)      string& assign (const string& str, size_t subpos, size_t sublen);
    
     复制从字符位置子座开始并跨越子字符的 str 部分(如果 str 太短或子词是字符串::npos,则直到 str 的末尾)。

    
str          另一个字符串对象,其值被复制或移动。

     子字
         str 中作为子字符串复制到对象的第一个字符的位置。如果这大于str的长度,则抛出out_of_range。注意:str 中的第一个字符用值 0(而不是 1)表示。

     苏普伦
         要复制的子字符串的长度(如果字符串较短,则复制尽可能多的字符)。 字符串::npos 的值表示 str 末尾之前的所有字符。

但是,我不确定这是否允许,或者它是否会损坏字符串数据。我知道memcpy() ,例如,不允许(或至少不保证在以下情况下不损坏)用自身(的一部分)覆盖内存区域(参见 memcpy() vs memmove())。但我不知道上述方法是否具有相同的限制。

更一般地说,您能否评论我是否应该自己找出这个问题的答案?我链接到的文档中没有任何内容让我清楚这个问题的答案是什么,除了 str 参数描述中的限定符"Other"("另一个字符串对象"),这似乎暗示它不可能是这个对象,尽管我不认为这是明确的。这是文档中的弱点吗?

No.

此操作由 [string::assign]/4 定义:

basic_string& assign(const basic_string& str, size_type pos,
    size_type n = npos);

效果:确定要分配的字符串的有效长度rlen 作为较小的nstr.size() - pos和呼叫assign(str.data() + pos rlen).

(打错字)

然后:

basic_string& assign(const charT* s, size_type n);

效果:将*this控制的字符串替换为字符串 长度n其元素是s所指元素的副本。

这并没有说明str.assign(str, 0)是否安全(特别是,我们无法知道每个字符的副本何时会出现!

因此,我强烈建议您避免这样做。

不要尝试。

它可能有效,但正如所选答案中所建议的那样,无法确保安全。 在最好的情况下,根据您的实现,将创建一个临时对象,然后销毁。

模拟它的一种方法如下,它

不会创建临时对象,并且确实比调用assignsubstr更快:

void trimTo(string & s, size_t pos = 0, size_t len = string::npos)
{ 
    s.erase(pos + len); 
    s.erase(pos, len); 
}

然后

trimTo(myString, fromPos, numChars);

工作为

myString.assign(myString.substr(fromPos, numChars);

但它至少快了两倍。

显然,这与 operator= (防止自我分配)的决定相同。

_Myt& assign(const _Myt& _Right,
    size_type _Roff, size_type _Count = npos)
    {   // assign _Right [_Roff, _Roff + _Count)
    _Right._Check_offset(_Roff);
    _Count = _Right._Clamp_suffix_size(_Roff, _Count);
    if (this == &_Right)
        erase((size_type)(_Roff + _Count)), erase(0, _Roff);    // substring
    else if (_Grow(_Count))
        {   // make room and assign new stuff
        _Traits::copy(this->_Myptr(),
            _Right._Myptr() + _Roff, _Count);
        _Eos(_Count);
        }
    return (*this);
    }