String: 常字符串

概要

这里讨论的是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类(如AutoFreeAllocScopeAlloc等)的实例。在构造函数带有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;

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);

相关参考

page_revision: 22, last_edited: 1206320229|%e %b %Y, %H:%M %Z (%O ago)
Unless stated otherwise Content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License