Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 您可以将std::string的子字符串分配给它自己吗?_C++_String - Fatal编程技术网

C++ 您可以将std::string的子字符串分配给它自己吗?

C++ 您可以将std::string的子字符串分配给它自己吗?,c++,string,C++,String,我最近发现需要将std::string的内容替换为其自身的子字符串。我认为在这里调用的最符合逻辑的函数如下所示: 子字符串(2)字符串和赋值(常量字符串和字符串、大小子字符串、大小子字符串) 复制str中从字符位置子项开始并跨越子项字符的部分(如果str太短或子项为string::npos,则复制到str的末尾) str 另一个字符串对象,其值被复制或移动 子项 str中作为子字符串复制到对象的第一个字符的位置。如果这大于str的长度,则抛出_范围之外的_。注意:str中的第一个字符由值0(不

我最近发现需要将
std::string
的内容替换为其自身的子字符串。我认为在这里调用的最符合逻辑的函数如下所示:

子字符串(2)字符串和赋值(常量字符串和字符串、大小子字符串、大小子字符串)

复制str中从字符位置子项开始并跨越子项字符的部分(如果str太短或子项为string::npos,则复制到str的末尾)

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

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

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

但是,我不确定这是否是允许的,或者它是否会损坏字符串数据。例如,我知道
memcpy()
,不允许(或至少不保证在这种情况下不会损坏)用自身(部分)覆盖内存区域(请参阅)。但我不知道上述方法是否也有同样的局限性

更一般地说,如果我自己能够找到这个问题的答案,你能评论一下吗?在我所链接的文档中,没有任何东西可以让我清楚地知道这个问题的答案是什么,除了
str
参数(“另一个字符串对象”)描述中的限定词“另一个”,这似乎意味着它不可能是this对象,尽管我不认为这是明确的。这是文档中的一个弱点吗?

否。

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

效果:确定要分配的字符串的有效长度
rlen
作为
n
str.size()-pos
中的较小者,调用
assign(str.data()+pos-rlen)

()

然后:

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

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

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

不要尝试那样做

它可能会起作用,但正如所选答案中所建议的,它不能确保安全。在最好的情况下,根据您的实现,将创建一个临时对象,然后将其销毁

模拟这种情况的一种方法是,它不创建临时对象,而且确实比调用
assign
substr
更快,如下所示:

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);

但它至少快了两倍。

显然,这与运算符=(防止自我分配)的决定是一样的


可分配C++类通常以安全的方式实现复制赋值操作符(即,它们检查分配<代码> *这= **此< /代码>)。标准容器类也不例外。但是,即使这样也不是必需的–字符串的子字符串不再是字符串本身。“Cplusplus.com”网站的措辞似乎也很糟糕——使用了“替换”一词,从中可以清楚地看出你所做的事情应该是安全的。@ParamagneticCroissant,为什么“替换”一词明确表示它应该是安全的?出于同样的原因,您可以说
memcpy()
替换了目标缓冲区的内容,但这并不意味着它是安全的。@bgoldst我相当确定,该标准没有完全涵盖此场景,因此无法使用它。如果您想保持安全,请使用
substr
和赋值运算符(即使用副本)。@dyp遗憾的是,这还不够。也许这应该是EWG问题的主题。@Columbo我怀疑它可能会以类似的方式结束。对于
vector::push_back
等,有人认为省略任何需求都会保证它表现良好(不允许失败)。libstdc++和libc++似乎支持显式分配别名字符串。@dyp:我看不出省略需求是如何隐式引入需求的!嗯,我是这样认为的,如果没有先决条件,那么人们可能会认为没有先决条件。但这都是猜测,我更愿意得出结论,除非这一点得到明确解决,否则从定义上讲,这是不安全的。@dyp在我读了你的链接后才刚刚想这么说。我相信只要参数合理,调用就可以了。@Columbo,当将字符串的一部分分配给它自己时,它总是重叠的,因为您将字符串的一部分分配给它自己。我认为规范是明确的。“替换字符串…其元素是s指向的元素的副本”-这意味着需要实现来确保它具有此效果。没有先决条件提到重叠输入。因此,使用重叠输入调用它必须是安全的,因为实现必须具有所描述的效果,很好地看到您引用的源代码的任何实现都可以防止这种情况。它是什么实现?什么版本?它随着时间的推移而改变了吗?其他实现怎么说?标准怎么说?这是否随着时间的推移而改变?代码片段取自VS 2015,因此我猜任何比它更新的MS STL代码都有它;这不是一个可靠的假设。
trimTo(myString, fromPos, numChars);
myString.assign(myString.substr(fromPos, numChars);
_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);
    }