简体   繁体   中英

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

I recently found the need to replace a std::string 's contents with a substring of itself. The most logical function to call here I think is the following, from http://www.cplusplus.com/reference/string/string/assign/ :

substring (2) string& assign (const string& str, size_t subpos, size_t sublen);

Copies the portion of str that begins at the character position subpos and spans sublen characters (or until the end of str, if either str is too short or if sublen is string::npos).

str
Another string object, whose value is either copied or moved.

subpos
Position of the first character in str that is copied to the object as a substring. If this is greater than str's length, it throws out_of_range. Note: The first character in str is denoted by a value of 0 (not 1).

sublen
Length of the substring to be copied (if the string is shorter, as many characters as possible are copied). A value of string::npos indicates all characters until the end of str.

However, I'm not certain if this is permissible, or if it can corrupt the string data. I know that memcpy() , for example, does not allow (or at least does not guarantee non-corruption in the case of) overwriting an area of memory with (a portion of) itself (see memcpy() vs memmove() ). But I don't know if the above method has the same limitation.

More generally, can you please comment if I should have been able to figure out the answer to this question myself? There's nothing in the documentation I linked to that makes it clear to me what the answer to this question is, except perhaps the qualifier "Another" in the description of the str parameter (" Another string object"), which seems to imply it cannot be the this object, although I don't find that to be unequivocal. Is that a weakness in the documentation?

No.

This operation is defined by [string::assign]/4:

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

Effects : Determines the effective length rlen of the string to assign as the smaller of n and str.size() - pos and calls assign(str.data() + pos rlen) .

( dat typo )

Then:

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

Effects : Replaces the string controlled by *this with a string of length n whose elements are a copy of those pointed to by s .

Nothing about this says anything about whether str.assign(str, 0) is at all safe (in particular, we have no way of knowing when the copy of each character will occur!).

Therefore I strongly suggest you avoid doing it.

Don't try that.

It may work, but as it is suggested in the selected answer, it is not ensured to be safe. In the best case, depending on your implementation, a temporary object would be created and then destroyed.

One way to emulate that, which does not create temporary objects and is indeed faster than calling to assign and substr is the following:

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

Then,

trimTo(myString, fromPos, numChars);

works as

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

but it's at least twice faster.

Apparently it was the same decision as with operator= (protect against self assignment).

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM