string::assign

#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)));
}
This entry was posted in C++ Language. Bookmark the permalink.

Leave a Reply