STL 源码剖析 string
最近打算好好看看STL源码实现...
各种定义找不到头都大了.
首先你需要一个帮手,ctags不行我们就用global(什么东西自己搞定,这么不介绍了).
在STL库的路径下 bits/stringfwd.h你能找到一下定义
你会发现我们常用的标准库类string实质上是basic_string
class string的定义有2000+行,我们这里不会给出所有细节,仅就个人觉得重要和感兴趣的地方进行分析.
你看,这里类的设计者把对于和string类的各种相关变量类型都做了声明,value_type, size_type ...
class _Rep用来表示字符串
string类总是用_M_length + 1个字符并且确保最后一个为‘\0‘空字符结尾来表示字符串.
而申请内存的时候总是会多申请一些(_M_capacity),_M_capacity 大于等于 _M_length.
上图是struct _Rep_base的定义,我们可以看到这里使用的是struct 而不是class,之前已经处于private标号中,所以整个结构体都是私有的.
注意到struct _Rep是 _Rep_base的派生类.
之后我们还能看到这里提供了string类的容量接口capacity()
这里STL的作者写了两个功能同样的接口,可能是为了便于程序员调用.size()与length()同一个意义,都返回当前字符串的长度,但是不包括空字符,这种风格和C的strlen()保持了一致.
我们写个小demo测试一下
#include <iostream> #include <string> using namespace std; int main() { string str("hello world"); cout << "capacity" << str.capacity() << endl; cout << "size " << str.size() << endl; cout << "length " << str.length() << endl; cout << "max_size" << str.max_size() << endl; return 0; }
你会看到各种构造函数的实现:
/** * @brief Construct an empty string using allocator @a a. */ explicit basic_string(const _Alloc& __a); /** * @brief Construct string with copy of value of @a str. * @param __str Source string. */ basic_string(const basic_string& __str); /** * @brief Construct string as copy of a substring. * @param __str Source string. * @param __pos Index of first character to copy from. * @param __n Number of characters to copy (default remainder). */ basic_string(const basic_string& __str, size_type __pos, size_type __n = npos); /** * @brief Construct string as copy of a substring. * @param __str Source string. * @param __pos Index of first character to copy from. * @param __n Number of characters to copy. * @param __a Allocator to use. */ basic_string(const basic_string& __str, size_type __pos, size_type __n, const _Alloc& __a); /** * @brief Construct string initialized by a character %array. * @param __s Source character %array. * @param __n Number of characters to copy. * @param __a Allocator to use (default is default allocator). * * NB: @a __s must have at least @a __n characters, '\\0' * has no special meaning. */ basic_string(const _CharT* __s, size_type __n, const _Alloc& __a = _Alloc()); /** * @brief Construct string as copy of a C string. * @param __s Source C string. * @param __a Allocator to use (default is default allocator). */ basic_string(const _CharT* __s, const _Alloc& __a = _Alloc()); /** * @brief Construct string as multiple characters. * @param __n Number of characters. * @param __c Character to use. * @param __a Allocator to use (default is default allocator). */
值得一提的是最后我们常用的字符串类初始化方式是给它一个C类型的字符串,作为初始化的参数.而这里其实就是调用的这里
basic_string(const _CharT* __s, const _Alloc& __a = _Alloc());
上面还给出了其他用字符串类引用做初始化参数的构造函数.
我们还看到了clear(), empty接口
clear()用于擦出字符串,使之为空.而empty()怎用于检测字符串是否为空.
#include <iostream> #include <string> using namespace std; int main() { string str("hello"); cout << "capacity" << str.capacity() << endl; cout << "size " << str.size() << endl; cout << "length " << str.length() << endl; cout << "max_size" << str.max_size() << endl; if (str.empty() == true) { cout << "empty" << endl; } else { cout << "Not empty" << endl; } str.clear(); if (str.empty() == true) { cout << "empty" << endl; } else { cout << "Not empty" << endl; } return 0; }
未完待更新~