#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
在實作上 以gcc4.8.5為例,它的libstdc++-v3 分別判斷了src/dest有無overlap(_M_disjunct)再進行處理
//libstdc++-v3/include/bits/basic_string.tcc templatebasic_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 templatebasic_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))); }