当编译string相关的代码出错时,常常会报一堆很长的错,其中会出现basic_string,如果你清楚string的定义,就不足为奇了:
template ,
class _Alloc =__STL_DEFAULT_ALLOCATOR(_CharT) >
class basic_string;
typedef basic_string string;
typedef basic_stringwstring;
string继承于_String_base: classbasic_string : private _String_base<_CharT,_Alloc> {... };
其内存管理与vector类似,也维护了三个指针变量:
using _Base::_M_start; //对应于begin
using _Base::_M_finish; //对应于end
using _Base::_M_end_of_storage; //对应于容量尾
这三个成员变量在_String_base中的属性为protected,由于是private继承,要使成员在子类中可见,需要使用using关键字。
以下是个private继承实例:
class Base
{
protected:
int data;
};
class Derived: private Base
{
public:
void setData(int a)data(a){}
int getData(){return data;}
protected:
using base::data;
};
在c语言中,字符串处理离开不了strlen,strcpy, strcat, strcmp, strstr等函数,string类作为char* 类型的一种封装,提供了自己的一套字符串操作接口:
substr //对应于用strcpy或strcat拷贝子串
append/insert //对应于strcat,append只用于尾部插入,insert可以在指定位置插入子串
find/rfind //对应于strstr, 查找函数有多个,其中rfind为反向查找
关系运算 > < == 或 compare(关系运算) //对应于strcmp
erase //删除指定区间的字符
c_str()/data() //从源码看c_str等价于data() 返回const char*字符串,其定义如下:
const_CharT* c_str() const { return _M_start; }
const_CharT* data() const { return _M_start;}
begin()/end()
[]/at //返回第i个字符元素,[]不提供范围检查,at提供范围检查,其源码如下
reference at(size_type __n) {
if (__n >= size())
_M_throw_out_of_range();
return *(_M_start + __n);
}
reference operator[](size_type __n)
{ return*(_M_start + __n); }
assign和= //赋值操作
swap //交换两个string
replace //替换string内容
完整的参数及形式可参考:标准C++中的string类的用法总结
sizeof(string) = 32; //相当于一个类的大小
string strArray[] = {"one","two", "three"}; //获取string数组的维数用sizeof(strArray)/ sizeof(string) 或sizeof(strArray) / sizeof(strArray[0])
用于函数的情况:void process(string strArray[]) //这边strArray已经是指针了,故sizeof(strArray) = 4
1) erase
其源码实现如下(其他形式的erase用法也是调用下面的方法):
iterator erase(iterator __first, iterator __last) {
if (__first != __last) {
// Themove includes the terminating null.
_Traits::move(__first, __last, (_M_finish - __last) + 1);
const iterator __new_finish = _M_finish - (__last - __first);
destroy(__new_finish + 1, _M_finish + 1);
_M_finish = __new_finish;
}
return __first;
}
从其中可以看出,调用erase只是析构了对象,并没有销毁空间,故string的size()不变。
replace。
string空间增长状况与vector的空间增长类似,内存管理也类似。
我们可以通过下面的代码了解到:
string str2;
for(int i = 0; i < 10; i++)
{
str2.append("1");
cout << "sizeof str2= " << str2.capacity() << endl;
}
将输出 1,2,4,8,16。
2) _M_insert_aux
string内存管理相关函数,想详细了解的话可以看源码,这边不做详细解释了,贴出源码如下(见
template
basic_string<_CharT,_Traits,_Alloc>::iterator
basic_string<_CharT,_Traits,_Alloc>
::_M_insert_aux(basic_string<_CharT,_Traits,_Alloc>::iterator __p,
_CharT __c)
{
iterator __new_pos = __p;
if(_M_finish + 1 < _M_end_of_storage) {
_M_construct_null(_M_finish + 1);
_Traits::move(__p + 1, __p, _M_finish - __p);
_Traits::assign(*__p, __c);
++_M_finish;
}
else {
const size_type __old_len = size();
const size_type __len = __old_len +
max(__old_len,static_cast(1)) + 1;
iterator __new_start = _M_allocate(__len);
iterator __new_finish = __new_start;
__STL_TRY {
__new_pos = uninitialized_copy(_M_start, __p, __new_start);
construct(__new_pos, __c);
__new_finish = __new_pos + 1;
__new_finish = uninitialized_copy(__p, _M_finish, __new_finish);
_M_construct_null(__new_finish);
}
__STL_UNWIND((destroy(__new_start,__new_finish),
_M_deallocate(__new_start,__len)));
destroy(_M_start, _M_finish + 1);
_M_deallocate_block();
_M_start = __new_start;
_M_finish = __new_finish;
_M_end_of_storage = __new_start + __len;
}
return __new_pos;
}
3) 关系运算符> < == 及 compare(关系运算)
int compare(const basic_string& __s)const
{ return_M_compare(_M_start, _M_finish, __s._M_start, __s._M_finish); }
//compare进行了重载,有多个版本,以上版本的参数是cont string
static int _M_compare(const _CharT* __f1, const _CharT* __l1,
const _CharT* __f2,const _CharT* __l2) {
const ptrdiff_t __n1 = __l1 - __f1; //字符串1长度
const ptrdiff_t __n2 = __l2 - __f2; //字符串2长度
const int cmp = _Traits::compare(__f1, __f2, min(__n1, __n2)); //只取n1 n2 中的较短的比较
return cmp != 0 ? cmp : (__n1 < __n2 ? -1 : (__n1 > __n2 ? 1 :0)); //最后结果需考虑n1 n2
}
注: ptrdiff_t定义为typedef ptrdiff_t difference_type;
对于关系运算,本质上都是调用的compare函数完成的,下面以< 为例说明
// Operator< (and also >, <=, and>=).
template
inline bool
operator<(constbasic_string<_CharT,_Traits,_Alloc>& __x,
const basic_string<_CharT,_Traits,_Alloc>& __y) {
return basic_string<_CharT,_Traits,_Alloc>
::_M_compare(__x.begin(), __x.end(), __y.begin(), __y.end()) < 0;
}
template
inline bool
operator<(const _CharT* __s,
const basic_string<_CharT,_Traits,_Alloc>& __y) {
size_t __n = _Traits::length(__s);
return basic_string<_CharT,_Traits,_Alloc>
::_M_compare(__s, __s + __n, __y.begin(),__y.end()) < 0;
}
template
inline bool
operator<(constbasic_string<_CharT,_Traits,_Alloc>& __x,
const _CharT* __s) {
size_t __n = _Traits::length(__s);
returnbasic_string<_CharT,_Traits,_Alloc>
::_M_compare(__x.begin(), __x.end(), __s, __s + __n) < 0;
}
从源码可知,关系运算符可处理string和string,string和char *,char*和string。如果比较char*和char*,请使用strcmp,或将其中一个char*转换成string。
4) find
template
basic_string<_CharT,_Traits,_Alloc>::size_type
basic_string<_CharT,_Traits,_Alloc>
::find(const _CharT* __s, size_type __pos, size_type __n) const
{
if(__pos + __n > size())
return npos; //查找失败返回npos
else {
const const_iterator __result =
search(_M_start + __pos, _M_finish,
__s, __s + __n, _Eq_traits<_Traits>());
return __result != _M_finish ? __result - begin() : npos; //查找失败返回npos
}
}
其中npos是个static变量,定义如下:
static const size_type npos;
template
constbasic_string<_CharT,_Traits,_Alloc>::size_type
basic_string<_CharT,_Traits,_Alloc>::npos
=(basic_string<_CharT,_Traits,_Alloc>::size_type) -1;
5) _M_range_initialize
用于构造string对象,其代码实现如下:
template
void _M_range_initialize(_ForwardIter __f, _ForwardIter __l,
forward_iterator_tag) {
difference_type __n = 0;
distance(__f, __l, __n);
_M_allocate_block(__n + 1);
_M_finish = uninitialized_copy(__f, __l, _M_start);
_M_terminate_string();
}
void _M_terminate_string() {
__STL_TRY {
_M_construct_null(_M_finish); //finish指针置空
}
__STL_UNWIND(destroy(_M_start, _M_finish));
}
void _M_construct_null(_CharT* __p) {
construct(__p);
# ifdef __STL_DEFAULT_CONSTRUCTOR_BUG
__STL_TRY {
*__p = (_CharT) 0;
}
__STL_UNWIND(destroy(__p));
# endif
}
欢迎转载,转载请注明出处!