如何实现std :: string(char * char_array)?

时间:2015-02-01 14:43:39

标签: c++ arrays string char

我很想知道字符串类如何实现从字符数组复制以初始化其内容。

我的猜测是这样的:

1:找到字符数组的长度,N。(这是怎么做的?粗略的方法是分别查看每个字符,直到找到空字符?是否使用了更好的方法?)

2:分配N个字节的存储空间。

3:使用strcpy逐字节复制每个元素。

显然这不是一个非常复杂的问题,我只是想知道以下内容是否(基本上或大致相同):

std::string program_name(argv[0]);

std::string program_name;
int length = 0;
while(*(argv[0] + length) != '/0')
    ++ length;
++ length; // Depends on whether string contains the null character - usually I don't think it does?
program_name.resize(length); // Maybe use reserve instead?
std::cpy(program_name.data(), argv[0], length - 1); // Don't copy the null character at the end

无论如何都是这样的。我没有尝试编译上面的伪代码,因为我对方法的概念感兴趣,而不是关于如何完成此操作的细节。

1 个答案:

答案 0 :(得分:3)

简而言之,您的实施几乎就是它的工作方式。

忽略std::stringstd::basic_string实现的事实,该std::string被模板化以处理存储在字符串中的各种数据类型(特别是“宽字符”),来自char *的std::string(const char* init_value) { size_t m_len = strlen(init_value); char *m_storage = new char[m_len+1]; std::copy(m_storage, init_value, m_len+1); } 构造函数可写成这样的东西:

template <class _CharT, class _Traits, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY
basic_string<_CharT, _Traits, _Allocator>::basic_string(const value_type* __s)
{
    _LIBCPP_ASSERT(__s != nullptr, "basic_string(const char*) detected nullptr");
    __init(__s, traits_type::length(__s));
#if _LIBCPP_DEBUG_LEVEL >= 2
    __get_db()->__insert_c(this);
#endif
}

当然,由于实际实现的继承和模板性质,实际实现将更加间接[可能具有“增长/分配”的特定功能]。

这是libcxx中的REAL实现:

__init

template <class _CharT, class _Traits, class _Allocator> void basic_string<_CharT, _Traits, _Allocator>::__init(const value_type* __s, size_type __sz) { if (__sz > max_size()) this->__throw_length_error(); pointer __p; if (__sz < __min_cap) { __set_short_size(__sz); __p = __get_short_pointer(); } else { size_type __cap = __recommend(__sz); __p = __alloc_traits::allocate(__alloc(), __cap+1); __set_long_pointer(__p); __set_long_cap(__cap+1); __set_long_size(__sz); } traits_type::copy(_VSTD::__to_raw_pointer(__p), __s, __sz); traits_type::assign(__p[__sz], value_type()); } 执行此操作:

new

它将一些技巧存储在指针内[并使用相关的分配器分配,可能不是traits_type::assign(__p[__sz], value_type());],并显式初始化结束标记[__init,作为对<{1}}可能会出现与C样式字符串不同的参数,因此无法保证结束标记。

traits_type::length()strlen

template <>
struct _LIBCPP_TYPE_VIS_ONLY char_traits<char>
{
...
    static inline size_t length(const char_type* __s) {return strlen(__s);}
....
};

当然,其他STL实现可能会使用不同的详细实现,但大致上它只是我的简化示例,但是为了应对许多类型和重用代码而更加混淆。