SGI的basic_string的代码分析
来源:互联网 发布:金融数据服务商排名 编辑:程序博客网 时间:2024/05/19 17:23
// 首先必须要了解的就是char_traits
#include <cstddef>
// 下面是string_char_traits,至于traits的好处,c-view的杂志里面已经有所描述
// TCPL里面也有描述
extern "C++" {
template <class charT>
struct string_char_traits {
typedef charT char_type; // for users to acquire the basic character type
// constraints,这些都是模板偏特化必须提供的
static void assign (char_type& c1, const char_type& c2)
{ c1 = c2; } // 给c1赋值 ,要求charT必须支持operator =()
static bool eq (const char_type& c1, const char_type& c2)
{ return (c1 == c2); } //返回c1是否eaqual c2 要求charT必须支持operator ==()
static bool ne (const char_type& c1, const char_type& c2)
{ return !(c1 == c2); } // not eaqual ,要求charT必须支持operator ==()
static bool lt (const char_type& c1, const char_type& c2)
{ return (c1 < c2); } // lower than,要求charT必须支持operator <()
static char_type eos () { return char_type(); }
// the null character ,注意 下面用char偏特化的时候,使用的是retuun 0
static bool is_del(char_type a) { return 0; }
// characteristic function for delimiters of charT
static int compare (const char_type* s1, const char_type* s2, size_t n)
{
size_t i;
for (i = 0; i < n; ++i)
if (ne (s1[i], s2[i]))
return lt (s1[i], s2[i]) ? -1 : 1;
return 0;
} // 比较s1,s2这两个指针开始的长度为n的字符串的大小,这里直接利用上面定义的成员函数完成的
// 当用char作为模板参数的时候,则是直接利用的memcmp, :)
static size_t length (const char_type* s) // 返回s的长度,以eos()表示字符串的结束,
{
size_t l = 0;
while (ne (*s++, eos ()))
++l;
return l;
}
static char_type* copy (char_type* s1, const char_type* s2, size_t n)
{
for (; n--; )
assign (s1[n], s2[n]);
return s1;
} //拷贝字符串,这里使用的是循环完成任务的,注意和偏特化方案的比较!
static char_type* move (char_type* s1, const char_type* s2, size_t n)
{
char_type a[n];
size_t i;
for (i = 0; i < n; ++i)
assign (a[i], s2[i]);
for (i = 0; i < n; ++i)
assign (s1[i], a[i]);
return s1;
} // 需要澄清的两点是:
// 1)move 并不是简单的“搬动”,s2里面的内容没有必要置NULL
// 为何不直接象copy一样,一次循环assign完成哪?不要奇怪,可以下面memcpy,memmove的比较
static char_type* set (char_type* s1, const char_type& c, size_t n)
{
for (; n--; )
assign (s1[n], c);
return s1;
} // 将s1开始的n个字符都赋值为c
};
class istream; // 这里仅仅是declare, 不是definition,可以多次declare,
class ostream;
#include <cctype>
#include <cstring>
struct string_char_traits <char> { // 对string_cahr_traits进行偏特化
typedef char char_type;
static void assign (char_type& c1, const char_type& c2)
{ c1 = c2; }
static bool eq (const char_type & c1, const char_type& c2)
{ return (c1 == c2); }
static bool ne (const char_type& c1, const char_type& c2)
{ return (c1 != c2); }
static bool lt (const char_type& c1, const char_type& c2)
{ return (c1 < c2); }
static char_type eos () { return 0; }
static bool is_del(char_type a) { return isspace(a); }
static int compare (const char_type* s1, const char_type* s2, size_t n)
{ return memcmp (s1, s2, n); }
static size_t length (const char_type* s)
{ return strlen (s); }
static char_type* copy (char_type* s1, const char_type* s2, size_t n)
{ return (char_type*) memcpy (s1, s2, n); }
// The memcpy function copies count bytes of src to dest.
// If the source and destination overlap,
// this function does not ensure that the original source bytes in the overlapping region are copied
// before being overwritten. Use memmove to handle overlapping regions.
static char_type* move (char_type* s1, const char_type* s2, size_t n)
{ return (char_type*) memmove (s1, s2, n); }
// The memmove function copies count bytes of characters from src to dest.
// If some regions of the source area and the destination overlap,
// memmove ensures that the original source bytes in the overlapping region are copied before being overwritten
static char_type* set (char_type* s1, const char_type& c, size_t n)
{ return (char_type*) memset (s1, c, n); }
};
#include <cwctype>
struct string_char_traits <wchar_t> {
typedef wchar_t char_type;
static void assign (char_type& c1, const char_type& c2)
{ c1 = c2; }
static bool eq (const char_type & c1, const char_type& c2)
{ return (c1 == c2); }
static bool ne (const char_type& c1, const char_type& c2)
{ return (c1 != c2); }
static bool lt (const char_type& c1, const char_type& c2)
{ return (c1 < c2); }
static char_type eos () { return 0; }
static bool is_del(char_type a) { return iswspace(a); }
static int compare (const char_type* s1, const char_type* s2, size_t n)
{ return wmemcmp (s1, s2, n); }
static size_t length (const char_type* s)
{ return wcslen (s); }
static char_type* copy (char_type* s1, const char_type* s2, size_t n)
{ return wmemcpy (s1, s2, n); }
static char_type* set (char_type* s1, const char_type& c, size_t n)
{ return wmemset (s1, c, n); }
};
} // extern "C++"
extern void __out_of_range (const char *);
extern void __length_error (const char *);
#define OUTOFRANGE(cond) /
do { if (cond) __out_of_range (#cond); } while (0)
#define LENGTHERROR(cond) /
do { if (cond) __length_error (#cond); } while (0)
// 注意这里的 “#cond” 这个 很有意思的用法, 看看下面这个用法 就知道了!
// #define print(arg) cout<<#arg " = "<<arg
// int main()
// { int a=1;
// print(a); }
// 可惜的是,怎么着都没有能够找到 __out_of_ranget(const char *) 此函数的定义所在!
// 整个OUTOFRANGE(cond) 这个宏的作用是 :判断cond条件,如果cond为真,
// 那么就调用__out_of_range(const char*)
// 而在此函数里面 则抛出一个异常! 估计带入的“#cond”就保存在该异常的内部,可以打印出来!
// LENGTHERROR(cond)宏的作用 和 OUTOFRANGE(cond)宏类似!
// 奇怪的是,这里的 do { } while(0) 的用法,有点匪夷所思!
// 除非带入的宏参数cond是一个复杂的“字符串”,cond其中含有“}” ,这样和"do { "恰好匹配
// 否则, 这里就相当于 “if (cond) __out_of_range (#cond);”
// do {} while(0) 根本起不到作用!
// basic_string 使用了 “引用计数”来实现string,这样可以减少内存分配的次数!
// 可以参考More effective Item 29
// 我们先来看basic_string的内部数据成员,仅仅包含两个
// 1)static Rep nilRep; // 初始化为 {0, 0, 1, false}
// 2)charT *dat; // 真正存放字符串(charT)的地方,动态allocate
// 乍一看上去,nilRep被定义成static,这和我们平时所看到的reference count很不相同
// 既然已经被定义成static数据成员,那么就会被basic_string<charT ...>的所有对象所共有
// 怎么还能用于reference count哪? 因为reference count里面的计数器只是针对具有相同“数据”的对象计数!
// 这里的nilRep的作用是 :对Empty string 进行计数!
// 而具有“真正有效数据的对象” 则 使用 另外一个 “隐式”的Rep对象进行计数
// 为什么,这里的Rep对象是“隐式”的哪? 因为该对象从始至终都没有一个自己的名字
// 在使用到此对象的时候都是使用 “reinterpret_cast” ,再加上内存地址运算 完成的,
// 可以看basic_string::Rep::data(),new(),delete(), create()等等!
// 我们就先参考basic_string::Rep::create(),大致了解一下basic_string的内部数据的安排情况!
template <class charT, class traits, class Allocator>
inline basic_string <charT, traits, Allocator>::Rep *
basic_string <charT, traits, Allocator>::Rep::
create (size_t extra)
{
extra = frob_size (extra + 1); // 这里经过计算得到一个比较适中的长度,后面再看
Rep *p = new (extra) Rep; // 这里刚看上去 好像适 new placement! 其实不是 :(
// new placement 的new定义为: void* operator new(size_t, void* pMem) { return pMem; }
// 你看到后面的这里的new的定义 ,你就会知道,其实这里是调用自己的new( sizeof(Rep), extra )
// 看到这个,你会发现 :在给字符串分配内存的时候,basic_string给你偷偷的添加了一个 “头”
// 这个头用于 记录该字符串的一系列信息! 但是这个头没有名字,所以一切的操作都不得不通过地址运算完成!
p->res = extra;
p->ref = 1; // 这三行都是给这个头信息自己的内部数据初始化!
p->selfish = false;
return p;
}
template <class charT, class traits, class Allocator>
inline void * basic_string <charT, traits, Allocator>::Rep::
operator new (size_t s, size_t extra)
{
return Allocator::allocate(s + extra * sizeof (charT));
//分配长度为 (sizeof(Rep)+实际字符串的capacity )的内存!
}
//知道了basic_string的内存模型,我们就可以来分析basic_string 的相关源代码了!
// 下面开始分析basic_string::Rep的结构!在了解了basic_string::Rep的结果之后,才能更好的明白basic_string的实现!
template <class charT, class traits = string_char_traits<charT>,
class Allocator = alloc >
class basic_string
{
private:
// 下面的struct Rep 是 basic_string的内部类Rep的定义,
struct Rep {
size_t len, res, ref;
// len --Rep 内部的有效数据的长度! --在basic_string::length()里面会表现出来
// res --分配的内存长度 --在basic_string::capacity()里面会表现出来
// ref -- reference count
bool selfish; // 用于标记 是否为私有!
charT* data () { return reinterpret_cast<charT *>(this + 1); }
// 注意这里的操作,这里(this +1)之后的地址,也就是字符串真正开始的地方--首地址!
// this+1 这个操作 相当于 &(*this)+sizeof(Rep)
charT& operator[] (size_t s) { return data () [s]; }
// 知道了字符串的首地址,求的第s个字符所在的地址
charT* grab () { if (selfish) return clone (); ++ref; return data (); }
// 大致的作用:如果selfish(完全私有),那么就拷贝一份返回
// 否则 直接将自己内部的字符串的首地址返回, 修改引用计数值
void release () { if (--ref == 0) delete this; }
// 这个和 普通引用计数里面的 用法一直,release的过程中,修改引用计数,如果没有引用了,那么释放内存
inline static void * operator new (size_t, size_t);
inline static void operator delete (void *);
inline static Rep* create (size_t); // 分配内存,参数为字符串实际占有的个数
charT* clone (); // 拷贝字符串
inline void copy (size_t, const charT *, size_t); // 分配新内存,拷贝字符串
inline void move (size_t, const charT *, size_t);
inline void set (size_t, const charT, size_t);
inline static bool excess_slop (size_t, size_t);
inline static size_t frob_size (size_t); // 计算
// 在后面!
private:
Rep &operator= (const Rep &); // 禁止operator=
};
};
// end of the Rep's Declaring
/// #include <std/bastring.cc>
// basic_string::Rep 的内部成员函数的定义
extern "C++" {
template <class charT, class traits, class Allocator>
inline void * basic_string <charT, traits, Allocator>::Rep::
operator new (size_t s, size_t extra)
{
return Allocator::allocate(s + extra * sizeof (charT));
} // 调用Allocator 分配内存, 这里的两个参数
// basic_string内部包含一个Rep指针对象,用于存储相关的一系列数据,另外还有用于存放char数组的对象
// s -- sizeof(Rep) , extra --basic_string 里面char数据的长度!
// 所以整个sizeof(basic_string)应该是 Rep的大小
// 将basic_string::Rep::operator new()和 basic_string::Rep::create 结合起来考察!
template <class charT, class traits, class Allocator>
inline void basic_string <charT, traits, Allocator>::Rep::
operator delete (void * ptr)
{
Allocator::deallocate(ptr, sizeof(Rep) +
reinterpret_cast<Rep *>(ptr)->res *
sizeof (charT)); // 了解了res的作用,也就明白这里的表达式
// res存放分配的字符串的个数,相当于basic_string::capacity()
}
template <class charT, class traits, class Allocator>
inline size_t basic_string <charT, traits, Allocator>::Rep::
frob_size (size_t s)
{
size_t i = 16;
while (i < s) i *= 2;
return i;
} // 为了和计算机的内存模型更匹配,这里计算得到实际分配的内存大小!
// 这里也就是如何计算字符串内存分配大小的策略!
template <class charT, class traits, class Allocator>
inline basic_string <charT, traits, Allocator>::Rep *
basic_string <charT, traits, Allocator>::Rep::
create (size_t extra)
{
extra = frob_size (extra + 1); // 计算实际分配的内存大小
Rep *p = new (extra) Rep; // Rep::operator new(), not placement!
// Rep的默认构造函数会 初始化len=0
p->res = extra; //存放内存实际大小!
p->ref = 1;
p->selfish = false;
return p;
}
template <class charT, class traits, class Allocator>
charT * basic_string <charT, traits, Allocator>::Rep::
clone ()
{
Rep *p = Rep::create (len); // 重新分配内存 ,这时候也就给新分配的内存添加“隐式”头--Rep
p->copy (0, data (), len); // 拷贝字符串
p->len = len;
return p->data ();
}
template <class charT, class traits, class Allocator>
inline bool basic_string <charT, traits, Allocator>::Rep::
excess_slop (size_t s, size_t r)
{
return 2 * (s <= 16 ? 16 : s) < r;
} // 和frob_size相似,这里仅仅判断s是否满足要求:参考Rep::frob_size
template <class charT, class traits, class Allocator>
inline bool basic_string <charT, traits, Allocator>::
check_realloc (basic_string::size_type s) const
{
s += sizeof (charT);
rep ()->selfish = false;
return (rep ()->ref > 1
|| s > capacity ()
|| Rep::excess_slop (s, capacity ()));
// 这三者为是否有必要重新分配内存的必要条件
}
template <class charT, class traits, class Allocator>
inline void basic_string <charT, traits, Allocator>::Rep::
copy (size_t pos, const charT *s, size_t n)
{
if (n)
traits::copy (data () + pos, s, n); // 这里利用到了char_traits, 会在后面提及
} // 将s的内容拷贝至this
template <class charT, class traits, class Allocator>
inline void basic_string <charT, traits, Allocator>::Rep::
move (size_t pos, const charT *s, size_t n)
{
if (n)
traits::move (data () + pos, s, n);
} // 将s的内容移动至this
template <class charT, class traits, class Allocator>
inline void basic_string <charT, traits, Allocator>::Rep::
set (size_t pos, const charT c, size_t n)
{
traits::set (data () + pos, c, n);
} // 将字符串中从pos开始的n个字符设置为字符c ,
// basic_string::Rep 分析结束!
真正的basic_String 开始 :
extern "C++" {
class istream; class ostream;
template <class charT, class traits = string_char_traits<charT>,
class Allocator = alloc >
class basic_string
{
public:
// types:
typedef traits traits_type;
typedef typename traits::char_type value_type;
typedef Allocator allocator_type;
// 下面的这些类型定义 是为了满足算法的要求,有了这些定义,string 就可以象vector一样的使用!
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef charT& reference;
typedef const charT& const_reference;
typedef charT* pointer;
typedef const charT* const_pointer;
typedef pointer iterator;
typedef const_pointer const_iterator;
typedef ::reverse_iterator<iterator> reverse_iterator; // ::运算符的作用
typedef ::reverse_iterator<const_iterator> const_reverse_iterator;
// 下面是basic_string的内部数据成员的定义
static const size_type npos = static_cast<size_type>(-1);
// 这里直接给出定义static变量,但是在class的外面,还需要declare一次
// 你也可以在class 里面declare,在外面definition
// npos 指
private:
static Rep nilRep; // 在class外面被初始化为 {0, 0, 1, false}
charT *dat; // 真正存放字符串(charT)的地方,动态allocate
private:
Rep * rep () const { return reinterpret_cast<Rep *>(dat) - 1; }
// 得到指向内部Rep对象(用于存放真正意义的字符串)的指针!
// 因为basic_string::dat 指向的是字符串真正开始的地方,
// 在this被强行转换为Rep*后,再-1,这时候的指针 就指向前面“隐式”的Rep对象了!
void repup (Rep *p) { rep ()->release (); dat = p->data (); }
// 这里看起来作用是 “给basic_string内部存放数据的dat重新赋值!”
// 所以整个的动作分为两步 : 1) 先release()原来自己的用的 2)再重新赋值
// 当然了,这时候会在适当的地方修改 “引用计数” !
public:
const charT* data () const
{ return rep ()->data(); } // 这里可以改为直接return dat ;
size_type length () const
{ return rep ()->len; } // rep()得到字符串前面的隐式的Rep头,里面保存了该字符串的一系列的内部信息!
size_type size () const
{ return rep ()->len; }
size_type capacity () const
{ return rep ()->res; } // 看到这里returnrep()->res; 也可以说明Rep::res的作用是记录字符串所占有的内存长度
size_type max_size () const
{ return (npos - 1)/sizeof (charT); } // XXX
// npos 就是 ( unsigned int) -1 , max_size 就是返回系统能够分配的最大字符(charT)数组的长度
bool empty () const
{ return size () == 0; }
// _lib.string.cons_ construct/copy/destroy:
basic_string& operator= (const basic_string& str)
{
if (&str != this) { rep ()->release (); dat = str.rep ()->grab (); }
return *this;
} // operator::=()必须要检验“自赋值”
// 第一步,肯定是release自己原来占有的了
// 第二步,赋予新的值,新的值可能是str的copy,也可能和str共有同一字符串,这是由Rep::grab()完成的!
explicit basic_string (): dat ( nilRep.grab () ) { }
// 不带任何参数的basic_string的构造函数,这里使用的是nilRep.grab()
// 可以看到空字符串是被单独处理的,他们都共同引用basic_string::nilRep.
// 而不是象其他非空字符串一样,先创建一个空字符串,然后大家再共同引用这个空字符串!
basic_string (const basic_string& str): dat ( str.rep ()->grab ()) { }
// copy-cotr! 和operator::=() 相似! 但是不需要再考虑自赋值
basic_string (const basic_string& str, size_type pos, size_type n = npos)
: dat (nilRep.grab ()) { assign (str, pos, n); }
basic_string (const charT* s, size_type n)
: dat (nilRep.grab ()) { assign (s, n); }
basic_string (const charT* s)
: dat (nilRep.grab ()) { assign (s); }
basic_string (size_type n, charT c)
: dat (nilRep.grab ()) { assign (n, c); }
template<class InputIterator>
basic_string(InputIterator begin, InputIterator end)
: dat (nilRep.grab ()) { assign (begin, end); }
// 以上几个构造函数,不错! :) 思路经典!一切都集中到了assign 成员函数上
~basic_string ()
{ rep ()->release (); } // 所有的认为(判断计数,释放内存)都由Rep::release()完成
void swap (basic_string &s) { charT *d = dat; dat = s.dat; s.dat = d; }
// :)
basic_string& append (const basic_string& str, size_type pos = 0,
size_type n = npos)
{ return replace (length (), 0, str, pos, n); }
basic_string& append (const charT* s, size_type n)
{ return replace (length (), 0, s, n); }
basic_string& append (const charT* s)
{ return append (s, traits::length (s)); }
basic_string& append (size_type n, charT c)
{ return replace (length (), 0, n, c); }
template<class InputIterator>
basic_string& append(InputIterator first, InputIterator last)
{ return replace (iend (), iend (), first, last); }
// append的工作都用replace完成!
basic_string& assign (const basic_string& str, size_type pos = 0,
size_type n = npos)
{ return replace (0, npos, str, pos, n); }
basic_string& assign (const charT* s, size_type n)
{ return replace (0, npos, s, n); }
basic_string& assign (const charT* s)
{ return assign (s, traits::length (s)); }
basic_string& assign (size_type n, charT c)
{ return replace (0, npos, n, c); }
template<class InputIterator>
basic_string& assign(InputIterator first, InputIterator last)
{ return replace (ibegin (), iend (), first, last); }
// assign 也由replace完成了
basic_string& operator= (const charT* s)
{ return assign (s); }
basic_string& operator= (charT c)
{ return assign (1, c); }
// 这个算是对operator =()的重载了
basic_string& operator+= (const basic_string& rhs)
{ return append (rhs); }
basic_string& operator+= (const charT* s)
{ return append (s); }
basic_string& operator+= (charT c)
{ return append (1, c); }
basic_string& insert (size_type pos1, const basic_string& str,
size_type pos2 = 0, size_type n = npos)
{ return replace (pos1, 0, str, pos2, n); }
basic_string& insert (size_type pos, const charT* s, size_type n)
{ return replace (pos, 0, s, n); }
basic_string& insert (size_type pos, const charT* s)
{ return insert (pos, s, traits::length (s)); }
basic_string& insert (size_type pos, size_type n, charT c)
{ return replace (pos, 0, n, c); }
iterator insert(iterator p, charT c)
{ size_type __o = p - ibegin ();
insert (p - ibegin (), 1, c); selfish ();
return ibegin () + __o; }
iterator insert(iterator p, size_type n, charT c)
{ size_type __o = p - ibegin ();
insert (p - ibegin (), n, c); selfish ();
return ibegin () + __o; }
template<class InputIterator>
void insert(iterator p, InputIterator first, InputIterator last)
{ replace (p, p, first, last); }
// insert 也由 replace完成
basic_string& erase (size_type pos = 0, size_type n = npos)
{ return replace (pos, n, (size_type)0, (charT)0); }
iterator erase(iterator p)
{ size_type __o = p - begin();
replace (__o, 1, (size_type)0, (charT)0); selfish ();
return ibegin() + __o; }
iterator erase(iterator f, iterator l)
{ size_type __o = f - ibegin();
replace (__o, l-f, (size_type)0, (charT)0);selfish ();
return ibegin() + __o; }
// erase也是 :(
basic_string& replace (size_type pos1, size_type n1, const basic_string& str,
size_type pos2 = 0, size_type n2 = npos);
basic_string& replace (size_type pos, size_type n1, const charT* s,
size_type n2); // declare,会在class之外给出定义
basic_string& replace (size_type pos, size_type n1, const charT* s)
{ return replace (pos, n1, s, traits::length (s)); }
basic_string& replace (size_type pos, size_type n1, size_type n2, charT c);
basic_string& replace (size_type pos, size_type n, charT c)
{ return replace (pos, n, 1, c); }
basic_string& replace (iterator i1, iterator i2, const basic_string& str)
{ return replace (i1 - ibegin (), i2 - i1, str); }
basic_string& replace (iterator i1, iterator i2, const charT* s, size_type n)
private:
static charT eos () { return traits::eos (); } // 字符串的结束标记,由char_traits给出各自的定义
// unique,selfish,operator []的配合使用,这里并没有使用proxy类(参考More Eff)
void unique () { if (rep ()->ref > 1) alloc (length (), true); }
// unique的作用:使自己不再和别人共有字符串数据,不得已的情况下,自己重新分配内存,将数据拷贝过来!
void selfish () { unique (); rep ()->selfish = true; }
public:
charT operator[] (size_type pos) const
{
if (pos == length ())
return eos ();
return data ()[pos]; // 根本没有判断越界,因为这里是const成员函数,不会修改内部数据,所以不要selfish
}
reference operator[] (size_type pos)
{ selfish (); //这里就不同了,害怕修改内部数据,所以必须事先做好准备,selfish!不再和别人共有数据了!
return (*rep ())[pos];
} // 这里的return 也可以和上面的一样写,return data()[pos],查看 Rep:operator[] 就知道了!
reference at (size_type pos)
{
OUTOFRANGE (pos >= length ()); // 判断是否越界! 会抛出异常!
return (*this)[pos]; // 这个用起basic_string:operator[]了! 呵呵!
// 在basic_string::operaotor[]里面做了selfish的工作,不要奇怪 :)
}
const_reference at (size_type pos) const // 这个是专门为const basic_string使用的!
{
OUTOFRANGE (pos >= length ());
return data ()[pos];
}
private:
void terminate () const
{ traits::assign ( ( *rep () )[length ()], eos () ); }
// 给字符串加了一个“结尾符”! 原来在basic_string的构造函数里面(在此里面利用的是replace)是没有结尾符的!
// 这里加上结尾符,为转换为CString做准备!
// 注意:basic_string内部字符串的有效范围是[0,length)
// 这里仅仅是在字符串的外面修改了一个“本来随机”的字符串为“结尾符”,
// 并没有修改原本有效的数据,也没有修改字符串的有效长度!
public:
const charT* c_str () const
{ if (length () == 0) return ""; terminate (); return data (); }
// 利用了terminate! 因为c_str是const成员函数,不会修改内部数据!
void resize (size_type n, charT c); // 在后面给出定义!
void resize (size_type n)
{ resize (n, eos ()); }
// 呵呵,所以这时候如果参数n>length(), 那么,有效字符串的后面就会有着“结尾符”!
// 那么cout<<basic_string::c_str<<1<<endl和cout<<basic_string的结果就不一样啦~~
/* # include <string>
#include <iostream>
int main()
{
string c="abc";
cout<<c<<1<<endl;
c.resize(5);
cout<<c<<1<<endl;
cout<<c.c_str()<<1<<endl;
} */
void reserve (size_type) { } // 强制分配内存,可能受到影响的仅仅是basic_string::capacity(),有效字符串的长度不变!
size_type copy (charT* s, size_type n, size_type pos = 0) const;
// Copies a substring of *this to a buffer.
size_type find (const basic_string& str, size_type pos = 0) const
{ return find (str.data(), pos, str.length()); }
size_type find (const charT* s, size_type pos, size_type n) const;
size_type find (const charT* s, size_type pos = 0) const
{ return find (s, pos, traits::length (s)); }
size_type find (charT c, size_type pos = 0) const;
// 正向查找
size_type rfind (const basic_string& str, size_type pos = npos) const
{ return rfind (str.data(), pos, str.length()); }
size_type rfind (const charT* s, size_type pos, size_type n) const;
size_type rfind (const charT* s, size_type pos = npos) const
{ return rfind (s, pos, traits::length (s)); }
size_type rfind (charT c, size_type pos = npos) const;
// 反向查找
size_type find_first_of (const basic_string& str, size_type pos = 0) const
{ return find_first_of (str.data(), pos, str.length()); }
size_type find_first_of (const charT* s, size_type pos, size_type n) const;
size_type find_first_of (const charT* s, size_type pos = 0) const
{ return find_first_of (s, pos, traits::length (s)); }
size_type find_first_of (charT c, size_type pos = 0) const
{ return find (c, pos); }
// 找正向的第一个字符(串)
size_type find_last_of (const basic_string& str, size_type pos = npos) const
{ return find_last_of (str.data(), pos, str.length()); }
size_type find_last_of (const charT* s, size_type pos, size_type n) const;
size_type find_last_of (const charT* s, size_type pos = npos) const
{ return find_last_of (s, pos, traits::length (s)); }
size_type find_last_of (charT c, size_type pos = npos) const
{ return rfind (c, pos); }
// 找正向的最后一个字符(串),即反向的第一个字符(串)!
size_type find_first_not_of (const basic_string& str, size_type pos = 0) const
{ return find_first_not_of (str.data(), pos, str.length()); }
size_type find_first_not_of (const charT* s, size_type pos, size_type n) const;
size_type find_first_not_of (const charT* s, size_type pos = 0) const
{ return find_first_not_of (s, pos, traits::length (s)); }
size_type find_first_not_of (charT c, size_type pos = 0) const;
// 正向找第一个字符(串)
size_type find_last_not_of (const basic_string& str, size_type pos = npos) const
{ return find_last_not_of (str.data(), pos, str.length()); }
size_type find_last_not_of (const charT* s, size_type pos, size_type n) const;
size_type find_last_not_of (const charT* s, size_type pos = npos) const
{ return find_last_not_of (s, pos, traits::length (s)); }
size_type find_last_not_of (charT c, size_type pos = npos) const;
// 反向找第一个不适合的字符(串)
basic_string substr (size_type pos = 0, size_type n = npos) const
{ return basic_string (*this, pos, n); }
// 这里返回的不是引用,而是一个basic_string对象
int compare (const basic_string& str, size_type pos = 0, size_type n = npos) const;
// There is no 'strncmp' equivalent for charT pointers.
int compare (const charT* s, size_type pos, size_type n) const;
int compare (const charT* s, size_type pos = 0) const
{ return compare (s, pos, traits::length (s)); }
iterator begin () { selfish (); return &(*this)[0]; }
iterator end () { selfish (); return &(*this)[length ()]; }
// 上面两个因为返回的是iterator,可以通过iterator修改字符串的内部数据,所以实现selfish,不再和别人共享数据!
// 这里终于不再使用rep()->data()来得到字符串数据了! 呵呵~
private:
iterator ibegin () const { return &(*rep ())[0]; }
iterator iend () const { return &(*rep ())[length ()]; }
public:
const_iterator begin () const { return ibegin (); }
const_iterator end () const { return iend (); }
// const iterator,没关系,无需selfish!
reverse_iterator rbegin() { return reverse_iterator (end ()); }
const_reverse_iterator rbegin() const
{ return const_reverse_iterator (end ()); }
reverse_iterator rend() { return reverse_iterator (begin ()); }
const_reverse_iterator rend() const
{ return const_reverse_iterator (begin ()); }
// 参考stl_iterator.h的分析!
private:
void alloc (size_type size, bool save);
static size_type _find (const charT* ptr, charT c, size_type xpos, size_type len);
inline bool check_realloc (size_type s) const;
//再class外面定义!
};
// 下面两个是basic_string 的内部的static 变量!
// 其中的npos是const,所以可以在class basic_string内部就可以直接给出定义,在外面声明即可;
// 当然也可和basic_string一样;而nilRep是nonconst,所以只能在class内部declare,在class外部definition
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>::Rep
basic_string<charT, traits, Allocator>::nilRep = { 0, 0, 1, false };
template <class charT, class traits, class Allocator>
const basic_string <charT, traits, Allocator>::size_type
basic_string <charT, traits, Allocator>::npos;
// 非内联的basic_string的成员函数
template <class charT, class traits, class Allocator>
inline bool basic_string <charT, traits, Allocator>::
check_realloc (basic_string::size_type s) const
{
s += sizeof (charT);
rep ()->selfish = false;
return (rep ()->ref > 1
|| s > capacity ()
|| Rep::excess_slop (s, capacity ()));
// 这三者为是否有必要重新分配内存的必要条件
}
//下面的alloc 就是分配内存!,
template <class charT, class traits, class Allocator>
void basic_string <charT, traits, Allocator>::
alloc (basic_string::size_type size, bool save)
{
if (! check_realloc (size))
return;
Rep *p = Rep::create (size); // 参考Rep的解释
if (save) // 是否需要保存原来的内容?
{
p->copy (0, data (), length ());
p->len = length ();
} // 再拷贝过去,修改“隐式”头的参数,其他的参数已经再Rep::create里面设置好了!
else
p->len = 0;
repup (p);
// void repup (Rep *p) { rep ()->release (); dat = p->data (); }
// :)看看如何使用的吧~~
}
// 下面是basic_string::replace的内容,可以参考数据结构!
// 由于代码较长,这里删除内部的实现细节,仅仅给出 成员函数原型!
// 可以在SGI的 bastring.cc和bastring.h文件里面找到!
// 参考SGI 的文档,可以知道这里的各自的作用!
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>&
basic_string <charT, traits, Allocator>::
replace (size_type pos1, size_type n1,
const basic_string& str, size_type pos2, size_type n2)
{ }
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>&
basic_string <charT, traits, Allocator>::
replace (size_type pos, size_type n1, const charT* s, size_type n2)
{ }
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>& basic_string <charT, traits, Allocator>::
replace (size_type pos, size_type n1, size_type n2, charT c)
{ }
template <class charT, class traits, class Allocator> template <class InputIterator>
basic_string <charT, traits, Allocator>& basic_string <charT, traits, Allocator>::
replace (iterator i1, iterator i2, InputIterator j1, InputIterator j2)
{ }
template <class charT, class traits, class Allocator>
void basic_string <charT, traits, Allocator>::
resize (size_type n, charT c)
{
LENGTHERROR (n > max_size ()); // 可千万别超过系统支持的最大长度 :)
if (n > length ())
append (n - length (), c);
else
erase (n);
} // resize会修改内部数据的! 和reserve()不同~
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>::size_type
basic_string <charT, traits, Allocator>::
copy (charT* s, size_type n, size_type pos) const
{
OUTOFRANGE (pos > length ());
if (n > length () - pos)
n = length () - pos;
traits::copy (s, data () + pos, n);
return n;
} // Copies a substring of *this to a buffer.
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>::size_type
basic_string <charT, traits, Allocator>::
find (const charT* s, size_type pos, size_type n) const
{ }
template <class charT, class traits, class Allocator>
inline basic_string <charT, traits, Allocator>::size_type
basic_string <charT, traits, Allocator>::
_find (const charT* ptr, charT c, size_type xpos, size_type len)
{ }
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>::size_type
basic_string <charT, traits, Allocator>::
find (charT c, size_type pos) const
{
return _find (data (), c, pos, length ());
}
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>::size_type
basic_string <charT, traits, Allocator>::
rfind (const charT* s, size_type pos, size_type n) const
{ }
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>::size_type
basic_string <charT, traits, Allocator>::
rfind (charT c, size_type pos) const
{ }
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>::size_type
basic_string <charT, traits, Allocator>::
find_first_of (const charT* s, size_type pos, size_type n) const
{ }
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>::size_type
basic_string <charT, traits, Allocator>::
find_last_of (const charT* s, size_type pos, size_type n) const
{ }
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>::size_type
basic_string <charT, traits, Allocator>::
find_first_not_of (const charT* s, size_type pos, size_type n) const
{ }
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>::size_type
basic_string <charT, traits, Allocator>::
find_first_not_of (charT c, size_type pos) const
{ }
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>::size_type
basic_string <charT, traits, Allocator>::
find_last_not_of (const charT* s, size_type pos, size_type n) const
{ }
template <class charT, class traits, class Allocator>
basic_string <charT, traits, Allocator>::size_type
basic_string <charT, traits, Allocator>::
find_last_not_of (charT c, size_type pos) const
{ }
template <class charT, class traits, class Allocator>
int basic_string <charT, traits, Allocator>::
compare (const basic_string& str, size_type pos, size_type n) const
{ }
template <class charT, class traits, class Allocator>
int basic_string <charT, traits, Allocator>::
compare (const charT* s, size_type pos, size_type n) const
{ }
// std下的全局函数,basic_string的相关操作
template <class charT, class traits, class Allocator>
inline basic_string <charT, traits, Allocator>
operator+ (const basic_string <charT, traits, Allocator>& lhs,
const basic_string <charT, traits, Allocator>& rhs)
{ }
template <class charT, class traits, class Allocator>
inline basic_string <charT, traits, Allocator>
operator+ (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs)
{ }
template <class charT, class traits, class Allocator>
inline basic_string <charT, traits, Allocator>
operator+ (charT lhs, const basic_string <charT, traits, Allocator>& rhs)
{ }
template <class charT, class traits, class Allocator>
inline basic_string <charT, traits, Allocator>
operator+ (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs)
{ }
template <class charT, class traits, class Allocator>
inline basic_string <charT, traits, Allocator>
operator+ (const basic_string <charT, traits, Allocator>& lhs, charT rhs)
{ }
template <class charT, class traits, class Allocator>
inline bool
operator== (const basic_string <charT, traits, Allocator>& lhs,
const basic_string <charT, traits, Allocator>& rhs)
{
return (lhs.compare (rhs) == 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator== (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs)
{
return (rhs.compare (lhs) == 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator== (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs)
{
return (lhs.compare (rhs) == 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator!= (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs)
{
return (rhs.compare (lhs) != 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator!= (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs)
{
return (lhs.compare (rhs) != 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator< (const basic_string <charT, traits, Allocator>& lhs,
const basic_string <charT, traits, Allocator>& rhs)
{
return (lhs.compare (rhs) < 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator< (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs)
{
return (rhs.compare (lhs) > 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator< (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs)
{
return (lhs.compare (rhs) < 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator> (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs)
{
return (rhs.compare (lhs) < 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator> (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs)
{
return (lhs.compare (rhs) > 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator<= (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs)
{
return (rhs.compare (lhs) >= 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator<= (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs)
{
return (lhs.compare (rhs) <= 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator>= (const charT* lhs, const basic_string <charT, traits, Allocator>& rhs)
{
return (rhs.compare (lhs) <= 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator>= (const basic_string <charT, traits, Allocator>& lhs, const charT* rhs)
{
return (lhs.compare (rhs) >= 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator!= (const basic_string <charT, traits, Allocator>& lhs,
const basic_string <charT, traits, Allocator>& rhs)
{
return (lhs.compare (rhs) != 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator> (const basic_string <charT, traits, Allocator>& lhs,
const basic_string <charT, traits, Allocator>& rhs)
{
return (lhs.compare (rhs) > 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator<= (const basic_string <charT, traits, Allocator>& lhs,
const basic_string <charT, traits, Allocator>& rhs)
{
return (lhs.compare (rhs) <= 0);
}
template <class charT, class traits, class Allocator>
inline bool
operator>= (const basic_string <charT, traits, Allocator>& lhs,
const basic_string <charT, traits, Allocator>& rhs)
{
return (lhs.compare (rhs) >= 0);
}
// 有关字符串的输入输出将会在 io分析过程中给出
} // extern "C++"
- SGI的basic_string的代码分析
- SGI STL红黑树中迭代器的边界值分析
- basic_string &assign 的使用
- string和basic_string的关系
- sgi的内存泄露
- sgi的hashtable
- SGI的内存管理
- 泛型<编程>:基于策略的basic_string实现
- SGI STL的内存池
- SGI STL的内存池
- STL SGI内存的管理
- SGI STL的内存分配器
- SGI STL的内存池
- SGI STL的内存池
- SGI STL 的内存管理
- SGI STL 的内存管理
- SGI STL 的内存管理
- SGI STL 的内存管理
- 2# Temporary Objects(临时对象)
- 30多个小时无位可坐,8旬老人猝死列车上
- 忙乎了一下午,终于将我的Blog搞定了;
- 积极主动、明确目标、掌握重点、利人利己、设身处地、集思广益、综合平衡
- 虽然我可能最近在学其他语言,但我最喜欢的还是 asm,c,c++
- SGI的basic_string的代码分析
- asp.net学习资源列表
- 无刷新下拉框
- 一些LINUX下的脚本
- 外资银行驻沪机构
- 酒
- Company Meeting
- metAmazon
- 该脚本剔除某目录下不规范的子目录名