字符串处理与string解析

basic_string为何物

         当编译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;
};

string常用操作

         在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的关系

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;

所以,使用string类的find函数时,请与string::npos比较看是否find成功。

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
  }

博客链接: http://blog.csdn.net/codingcs

欢迎转载,转载请注明出处!

你可能感兴趣的:(C/C++)