#include
#include
int main()
{
std::string x("0123456789");
x.assign(x.data() + 3, 5);
std::cout << x << std::endl; //34567
}
以上的string assign在src和dest即使有overlapped,在C++標準中,這樣是不會有問題的。
參考c++03
21.3.5.3 basic_string::assign
basic_string < charT , traits , Allocator >&
assign ( const charT * s , size_type n );
Returns: assign(basic_string(s ,n ))
在實作上 以gcc4.8.5為例,它的libstdc++-v3 分別判斷了src/dest有無overlap(_M_disjunct)再進行處理
//libstdc++-v3/include/bits/basic_string.tcc
template
basic_string<_CharT, _Traits, _Alloc>&
basic_string<_CharT, _Traits, _Alloc>::
assign(const _CharT* __s, size_type __n)
{
__glibcxx_requires_string_len(__s, __n);
_M_check_length(this->size(), __n, "basic_string::assign");
if (_M_disjunct(__s) || _M_rep()->_M_is_shared())
return _M_replace_safe(size_type(0), this->size(), __s, __n);
else
{
// Work in-place.
const size_type __pos = __s - _M_data();
if (__pos >= __n)
_M_copy(_M_data(), __s, __n);
else if (__pos)
_M_move(_M_data(), __s, __n);
_M_rep()->_M_set_length_and_sharable(__n);
return *this;
}
}
儘管規範如此,在呼叫API時,碰到可能會有修改到自身的內部狀態時,要特別小心規範是否支援以及實作是否正確
以stlport 5.2.1為例,沒有特別處理overlap問題,而是直接_Traits::copy => memcpy(並不保證overlapped沒問題 要看memcpy實作, 如果要移動overlapped region, 應該用memmove, => _Traits::move),因此碰到overlapped的情況會有問題
// stl/stlport/_string.c
template
basic_string<_CharT,_Traits,_Alloc>&
basic_string<_CharT,_Traits,_Alloc>::_M_assign(const _CharT* __f, const _CharT* __l) {
ptrdiff_t __n = __l - __f;
if (__STATIC_CAST(size_type, __n) <= size()) {
_Traits::copy(this->_M_Start(), __f, __n);
erase(begin() + __n, end());
}
else {
_Traits::copy(this->_M_Start(), __f, size());
_M_append(__f + size(), __l);
}
return *this;
}
// stl/stlport/char_traits.h
static char_type* _STLP_CALL copy(char_type* __s1, const char_type* __s2, size_t __n) {
return (__n == 0 ? __s1 :
(char_type*)memcpy(__s1, __s2, __n * sizeof(char_type)));
}