C++標准庫中對std::string使用不合法(空指針或不以'\0'結尾)的c風格字符串(c style string)初始化的處理


使用c風格字符串初始化std::string時存在兩種可能的錯誤情況:

  1. 傳入空指針,
  2. 傳入的c風格字符串不以'\0'結尾。

g++ (GCC) 11.2.0 中,使用c風格字符串初始化 std::string(basic_string)的代碼如下:

basic_string(const _CharT* __s, const _Alloc& __a = _Alloc())
    : _M_dataplus(_M_local_data(), __a)
    {
        const _CharT* __end = __s ? __s + traits_type::length(__s)
            // We just need a non-null pointer here to get an exception:
            : reinterpret_cast<const _CharT*>(__alignof__(_CharT));
        _M_construct(__s, __end, random_access_iterator_tag());
    }

第4-6行的三目運算符作用如下:如果__s是一個空指針,則將__end設置為1;否則調用下列函數(進而調用libc中的strlen。錯誤1使用不以'\0'結尾的字符串調用strlen是未定義行為(The behavior is undefined if str is not a pointer to a null-terminated byte string.https://en.cppreference.com/w/c/string/byte/strlen)),將__end設置為滿足迭代器要求的指針位置(字符串末尾'\0'的位置)。

static _GLIBCXX17_CONSTEXPR size_t
    length(const char_type* __s)
{
    #if __cplusplus >= 201703L
    if (__constant_string_p(__s))
        return __gnu_cxx::char_traits<char_type>::length(__s);
    #endif
    return __builtin_strlen(__s);
}

_M_construct進一步調用下列函數,錯誤2如果第一步傳入的__s為空指針,這里第9-11行會拋出異常.

經過一系列錯誤檢查,在17行創建內部c string空間,在23行進行字符串拷貝

template<typename _CharT, typename _Traits, typename _Alloc>
template<typename _InIterator>
void
basic_string<_CharT, _Traits, _Alloc>::
_M_construct(_InIterator __beg, _InIterator __end,
             std::forward_iterator_tag)
{
    // NB: Not required, but considered best practice.
    if (__gnu_cxx::__is_null_pointer(__beg) && __beg != __end)
        std::__throw_logic_error(__N("basic_string::"
                                     "_M_construct null not valid"));

    size_type __dnew = static_cast<size_type>(std::distance(__beg, __end));

    if (__dnew > size_type(_S_local_capacity))
    {
        _M_data(_M_create(__dnew, size_type(0)));
        _M_capacity(__dnew);
    }

    // Check for out_of_range and length_error exceptions.
    __try
    { this->_S_copy_chars(_M_data(), __beg, __end); }
    __catch(...)
    {
        _M_dispose();
        __throw_exception_again;
    }

    _M_set_length(__dnew);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM