10. reserve和resize函数
reserve函数:
reserve(size_type __res)
{
if (__res != this->capacity() || _M_rep()->_M_is_shared())
{
if (__res > this->max_size())
__throw_length_error(__N("basic_string::reserve"));
// Make sure we don't shrink below the current size
if (__res < this->size())
__res = this->size();
//在这里不管如何都会新生成一份copy,其实我觉得也不一定的,特别是上面的if为真,并且没有对象共享的时候,不需要重新clone的。
const allocator_type __a = get_allocator();
_CharT* __tmp = _M_rep()->_M_clone(__a, __res - this->size());
_M_rep()->_M_dispose(__a);
_M_data(__tmp);
}
}
resize函数:
resize(size_type __n, _CharT __c)
{
if (__n > max_size())
__throw_length_error(__N("basic_string::resize"));
const size_type __size = this->size();
if (__size < __n)
this->append(__n - __size, __c);
else if (__n < __size)
//当有string对象共享的时候,会重新分配空间,当没有对象共享的时候,实际上erase什么也没有做。
this->erase(__n);
}
11. swap函数
swap(basic_string& __s)
{
//在这个函数中,开头的两个if判断很有意思,我猜测就是上述insert、Erase、operator[]操作之后的string对象,因为swap之后,用户应该明白以前的迭代器都失效了,所以重新设置为单一对象标志。
if (_M_rep()->_M_is_leaked())
_M_rep()->_M_set_sharable();
if (__s._M_rep()->_M_is_leaked())
__s._M_rep()->_M_set_sharable();
//分配器相同的话直接交换指针
if (this->get_allocator() == __s.get_allocator())
{
_CharT* __tmp = _M_data();
_M_data(__s._M_data());
__s._M_data(__tmp);
}
else
{
//否则不仅仅交换数据还要交换分配器的类型
const basic_string __tmp1(_M_ibegin(), _M_iend(),
__s.get_allocator());
const basic_string __tmp2(__s._M_ibegin(), __s._M_iend(),
this->get_allocator());
*this = __tmp2;
__s = __tmp1;
}
}
12. append和operator+函数
append函数:
append(const basic_string& __str)
{
//在源代码中有一段注释,说明了为什么引入临时变量__size,主要是为了防止appending自身,修改了他自身的长度
const size_type __size = __str.size();
const size_type __len = __size + this->size();
if (__len > this->capacity())
this->reserve(__len);
return _M_replace_safe(this->size(), size_type(0), __str._M_data(), __str.size());
}
这个也比较简单,也调用了_M_repalce_safe函数。append函数共有三个重载形式,基本都是相同的代码。
Operator+函数:
operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs,constbasic_string<_CharT, _Traits, _Alloc>& __rhs)
{
basic_string<_CharT, _Traits, _Alloc> __str(__lhs);
__str.append(__rhs);
return __str;
}
Operator共有5个重载函数,实现基本都类似于上面的函数直接调用append函数完成。
13. 其他函数
除了上述比较关键的函数意外,Basic_string模版类也提供其他的函数。
Ø 逻辑关系运算的函数,他们都是直接调用字符模板的函数完成的,如:<,>,==,!=等(有的函数还有多个重载形式);
Ø 纯算法型函数,find,find_of,find_first_of,find_first_not_of,find_last_of,find_last_not_of,rfind,rend等函数(有的函数还有多个重载形式)。提供这些函数的目的主要是为了效率和string种独特的操作(这些函数在很多书籍中都有很详细的使用介绍,其实现也不难);
Ø STL容器必须支持的函数,如begin,end,empty等函数;
Ø Operator<<,operator>>,getline函数这是使用GNU的扩展语法,其中他们的定义分别在istream.tcc和ostream.tcc中,在这里仅仅是引入模板类的声明;
Ø 最后还有就是string特有的函数,如c_str函数(返回字符串),length等函数。
14. 调试版本的string
在SGI STL中还提供了调试版本的string模版本,调试状态下的string主要继承于basic_string模板了以及_Safe_sequence模板类。前者就是我们上面所分析的代码,后者主要增加一些额外的调试信息。_Safe_sequence模板类继承于_Safe_sequence_base,主要保证经过操作之后迭代器是有效的。
15. 参考文献
主要是参考了SGI STL中的源文件Basic_string.h和Basic_string.tcc,其中这两个文件实现了basic_string模板类的所有函数。注意SGI STL中的*.tcc文件一般是对应于*.h中部分函数的实现和静态成员变量的定义。