|
Table of Contents
|
概要
这里讨论的是std::String,不是STL中的std::string,尽管两者名字如此之像。如果你感兴趣的是后者,请参考这里。
std::String是常字符串类。它类似于Java语言中的String类。关于它实现细节的详细说明,参考《C/C++字符串处理(2):String - 常字符串》。
规格
template <class _E> class BasicString : public TempString<_E> { public: // 构造函数 BasicString(); BasicString(const value_type* pszVal, size_type cch); BasicString(const BasicString& src, size_type from, size_type cch = (size_type)-1); template <class AllocT> BasicString(AllocT& alloc, const TempString<_E> b); template <class AllocT> BasicString(AllocT& alloc, const value_type* pszVal, size_type cch); template <class AllocT> BasicString(AllocT& alloc, size_type count, value_type ch); template <class AllocT, class Iterator> BasicString(AllocT& alloc, Iterator first, Iterator last); public: // 将其他线性容器转换为一个临时的String(这并不产生副本,是很轻的操作)。 static BasicString cast(const basic_string<_E>& src); static BasicString cast(const vector<_E>& builder); // 求子字符串。这也是一个非常轻的操作。 BasicString substr(size_type from = 0, size_type count = (size_type)-1) const; public: // 这个assign没有产生复制,其实是attach操作。 BasicString& assign(const BasicString& src, size_type from, size_type cch = (size_type)-1); public: // 赋值操作(这里进行了真正的复制) template <class AllocT> BasicString& assign(AllocT& alloc, const TempString<_E> b); template <class AllocT> BasicString& assign(AllocT& alloc, const value_type* pszVal, size_type cch); template <class AllocT> BasicString& assign(AllocT& alloc, size_type count, value_type ch); template <class AllocT, class Iterator> BasicString& assign(AllocT& alloc, Iterator first, Iterator last); public: // 在字符串中查找子串(正向查找)。 iterator find(const TempString<_E> pattern, iterator from = begin()) const; iterator find(const _E* pattern, size_type len, iterator from = begin()) const; public: // 在字符串中查找子串(反向查找)。 iterator rfind(const TempString<_E> pattern, iterator from = begin()) const; iterator rfind(const _E* pattern, size_type len, iterator from = begin()) const; public: // 查找某个集合中的字符在字符串中第一次出现的位置(正向查找)。 iterator find_first_of(const TempString<_E> pattern, iterator from = begin()) const; iterator find_first_of(const _E* pattern, size_type len, iterator from = begin()) const; public: // 查找某个集合中的字符在字符串中第一次出现的位置(反向查找)。 reverse_iterator find_last_of(const TempString<_E> pattern, reverse_iterator from = rbegin()) const; reverse_iterator find_last_of(const _E* pattern, size_type len, reverse_iterator from = rbegin()) const; public: // 在字符串中查找不在集合中出现的第一个字符的位置(正向查找)。 iterator find_first_not_of(const TempString<_E> pattern, iterator from = begin()) const; iterator find_first_not_of(const _E* pattern, size_type len, iterator from = begin()) const; public: // 在字符串中查找不在集合中出现的第一个字符的位置(反向查找)。 reverse_iterator find_last_not_of(const TempString<_E> pattern, reverse_iterator from = rbegin()) const; reverse_iterator find_last_not_of(const _E* pattern, size_type len, reverse_iterator from = rbegin()) const; public: // 比较两个字符串。 int compare(const TempString<_E> b) const; int compare(const _E* b, size_type blen) const; int compare(size_type from, size_type count, const TempString<_E> b) const; int compare(size_type from, size_type count, const _E* b, size_type blen) const; public: // 比较两个字符串(传入单字符的比较函数)。 template <class _Compr> int compare_by(const TempString<_E> b, _Compr cmp) const; template <class _Compr> int compare_by(const _E* b, size_type blen, _Compr cmp) const; public: // 比较两个字符串(忽略大小写)。 int icompare(const TempString<_E> b) const; int icompare(const _E* b, size_type blen) const; public: // 判断是否包含指定的串。 bool contains(const TempString<_E> b) const; bool contains(const _E* b, size_type blen) const; }; typedef BasicString<char> String; typedef BasicString<WCHAR> WString; template <class _E> bool operator<cmp>(const BasicString<_E>& a, const BasicString<_E>& b); // 比较两个字符串。 // 这里<cmp>是各种比较的算符,如==、!=、<、<=、>、>=等等。 template <class AllocT, class _E> // 多个字符串连接。 BasicString<_E> concat(Alloc& alloc, TempString<_E> a1, TempString<_E> a2, ...);
_E
- 字符类型。如char、WCHAR等。
AllocT
该如何理解TempString?
从字面意思来讲,这是一个临时字符串类。为什么它会是String(即BasicString)的基类?这其实只是实现上的需要。TempString理论上就是String(只是有特殊的生命周期),和BasicString规格一致。之所以它最后成为BasicString的基类,完全是实现上方便的考虑。
以BasicString::compare为例,我们考察以下这个函数:
int BasicString::compare(const TempString<_E> b) const;
这个函数的含义非常丰富。相当于定义了以下这一系列的函数:
int BasicString::compare(const _E& b) const; // 与包含单个字符b的字符串比较 int BasicString::compare(const _E* b) const; // 与C Style风格的字符串b比较 int BasicString::compare(const basic_string<_E>& b) const; // 与STL string比较 int BasicString::compare(const BasicString<_E>& b) const; // 与另一个常String比较 int BasicString::compare(const vector<_E>& b) const; // 与向量表示的字符串b比较 int BasicString::compare(const BasicStringBuilder<_E>& b) const;
一个函数可抵6个函数!
你已经看到,BasicString中大量使用TempString来进行规格定义。这种方式的代码伸缩性无疑相当好。TempString的构造每增加一种线性字符串的支持,BasicString的所有相关操作即可立即支持该类型的字符串表示。
关于std::TempString的详细说明,参见TempString。
构造函数
BasicString(); BasicString(const value_type* pszVal, size_type cch); BasicString(const BasicString& src, size_type from, size_type cch = (size_type)-1); template <class AllocT> BasicString(AllocT& alloc, const TempString<_E> b); template <class AllocT> BasicString(AllocT& alloc, const value_type* pszVal, size_type cch); template <class AllocT> BasicString(AllocT& alloc, size_type count, value_type ch); template <class AllocT, class Iterator> BasicString(AllocT& alloc, Iterator first, Iterator last);
alloc
- GC Allocator类(如AutoFreeAlloc、ScopeAlloc等)的实例。在构造函数带有alloc参数时,将进行字符串内容的复制操作。否则仅仅进行指针赋值。
该如何理解BasicString?
你可能奇怪,为什么BasicString没有这样的构造函数:
BasicString(const value_type* pszVal);
或者,你奇怪为什么有:
BasicString(const value_type* pszVal, size_type cch); template <class AllocT> BasicString(AllocT& alloc, const value_type* pszVal, size_type cch);
这两者有何不同?
StdExt的String(BasicString),和你以前见过的所有字符串类都不太一样。它的特别之处在于,它并不维护字符串的生命周期。这可能让你诧异:居然会有这样字符串类,它并不管理字符串的生命周期。
但是我们这样做了。而这的确给我们带来很多便利。例如:
- 赋值(复制)、子串(substr)是非常轻量的操作。Copy-On-Write技术完全是多余的。
- 可以将任意的线性容器(如std::vector、std::basic_string)临时转换为String(非常轻量)。参见下文中对String::cast方法的介绍。
为什么String类可以不管理自己的生命周期?这就是我们StdExt的内存管理变革倡导的思想了。
再看这两个构造函数:
BasicString(const value_type* pszVal, size_type cch); template <class AllocT> BasicString(AllocT& alloc, const value_type* pszVal, size_type cch);
这表示:第一个构造函数传入的pszVal,其生命周期比BasicString长(到BasicString析构时仍然有效)。而第二个构造函数的意思是,pszVal是一个临时有效的字符串,这个构造函数将拷贝一个pszVal字符串的副本。
为什么不支持 BasicString(const value_type* pszVal) 这样的构造?
很简单,这个构造过于危险,我不能确定你的意图是什么。
cast - 类型转换
static BasicString cast(const basic_string<_E>& src); static BasicString cast(const vector<_E>& builder);
- 将其他线性容器转换为一个临时的String(这并不产生副本,是很轻的操作)。这要求在生成的BasicString析构前,所基于的容器(上面的src或builder)不被销毁或修改。
substr - 取子字符串
BasicString substr(size_type from = 0, size_type count = (size_type)-1) const;
- 如前“该如何理解BasicString”所述,取子字符串也是一个非常轻的操作。所执行的仅仅是指针赋值。
assign - 赋值
BasicString& assign( const BasicString& src, size_type from, size_type cch = (size_type)-1); template <class AllocT> BasicString& assign(AllocT& alloc, const TempString<_E> b); template <class AllocT> BasicString& assign(AllocT& alloc, const value_type* pszVal, size_type cch); template <class AllocT> BasicString& assign(AllocT& alloc, size_type count, value_type ch); template <class AllocT, class Iterator> BasicString& assign(AllocT& alloc, Iterator first, Iterator last);
- 这里的assign和构造函数一样,有两种含义:一种是那些不带alloc参数的,它们其实没有产生复制,是attach操作。而另一种带alloc参数的,他们进行了真正的内存复制。详细参见“构造函数”一节。
find - 在字符串中查找子串(正向查找)
iterator find(const TempString<_E> pattern, iterator from = begin()) const; iterator find(const _E* pattern, size_type len, iterator from = begin()) const;
rfind - 在字符串中查找子串(反向查找)
iterator rfind(const TempString<_E> pattern, iterator from = begin()) const; iterator rfind(const _E* pattern, size_type len, iterator from = begin()) const;
find_first_of - 在字符串中查找集合中的字符之一(正向)
iterator find_first_of( const TempString<_E> pattern, iterator from = begin()) const; iterator find_first_of( const _E* pattern, size_type len, iterator from = begin()) const;
- 查找某个集合中的字符在字符串中第一次出现的位置(正向查找)。
find_last_of - 在字符串中查找集合中的字符之一(反向)
reverse_iterator find_last_of( const TempString<_E> pattern, reverse_iterator from = rbegin()) const; reverse_iterator find_last_of( const _E* pattern, size_type len, reverse_iterator from = rbegin()) const;
- 查找某个集合中的字符在字符串中第一次出现的位置(反向查找)。
find_first_not_of - 在字符串中查找非集合中的任意字符(正向)
iterator find_first_not_of( const TempString<_E> pattern, iterator from = begin()) const; iterator find_first_not_of( const _E* pattern, size_type len, iterator from = begin()) const;
- 在字符串中查找不在集合中出现的第一个字符的位置(正向查找)。
find_last_not_of - 在字符串中查找非集合中的任意字符(正向)
reverse_iterator find_last_not_of( const TempString<_E> pattern, reverse_iterator from = rbegin()) const; reverse_iterator find_last_not_of( const _E* pattern, size_type len, reverse_iterator from = rbegin()) const;
- 在字符串中查找不在集合中出现的第一个字符的位置(反向查找)。
compare - 比较两个字符串
int compare(const TempString<_E> b) const; int compare(const _E* b, size_type blen) const; int compare(size_type from, size_type count, const TempString<_E> b) const; int compare(size_type from, size_type count, const _E* b, size_type blen) const;
- 相关的全局函数如下:
template <class _E> bool operator<cmp>(const BasicString<_E>& a, const BasicString<_E>& b); // 比较两个字符串。这里<cmp>是各种比较的算符,如==、!=、<、<=、>、>=等等。
compare_by - 比较两个字符串(传入单字符的比较函数)
template <class _Compr> int compare_by(const TempString<_E> b, _Compr cmp) const; template <class _Compr> int compare_by(const _E* b, size_type blen, _Compr cmp) const;
_Compr cmp
- 单字符比较函数(或仿函数)。仿函数规格要求:
template <class _E> struct _Compr { int operator()(_E a, _E b); };
icompare - 比较两个字符串(忽略大小写)
int icompare(const TempString<_E> b) const; int icompare(const _E* b, size_type blen) const;
contains - 判断是否包含指定的串
bool contains(const TempString<_E> b) const; bool contains(const _E* b, size_type blen) const;
concat - 字符串连接
template <class AllocT, class _E> // 多个字符串连接。 BasicString<_E> concat(Alloc& alloc, TempString<_E> a1, TempString<_E> a2, ...);
- concat并非是BasicString类的成员函数。而是与BasicString有密切关系的全局函数。对于STL string类,你通常被推荐用operator+或者string::append函数来进行字符串连接。如:
std::string a = std::string("Hello") + " " + "world" + "!!!";
- 对应地,BasicString并无operator+或者append,它使用全局的std::concat函数进行字符串连接。如下:
std::String a = std::concat(alloc, "Hello", " ", "world", "!!!");
- 有意思的是,这个std::concat不只可以高效地连接任意多的字符串,而且,它还可以连接高效地连接各种线性的字符串表示,包括:char*, std::string, std::vector<char>, std::String, std::StringBuilder等。例如:
std::string hello = "Hello"; std::String space(" ", 1); std::vector<char> excalmatory_mark(3, '!'); std::String a = std::concat(alloc, hello, space, "world", excalmatory_mark);
- 这其中的奥秘,全在TempString上,在上面我们已经大致解释其中缘由。关于std::concat的实现,详细请参见concat。





