string类是基于下述模板定义的:
template<class charT,class traits = char_traits<charT>,
class Allocator = allocator<charT> >
class basic_string { ... };
其中,charT是存储在字符串中的类型;traits参数是一个类,它定义了类型要被表示为字符串时,所必须具备的特征。
例如,它必须有length()方法,该方法返回被表示为charT数组的字符串的长度。这种数组结尾用charT(0)值(广义的空值字符)表示(表达式charT(0)将0转换为charT类型。它可以像类型为char时那样为零,也可以是charT的一个构造函数创建的对象)。这个类还包含用于对值进行比较等操作的方法。
Allocator参数是用于处理字符串内存分配的类。默认的allocator<char>模板按标准方式使用new和delete。
两种预定义的具体化:
typedef basic_string<char> string;
typedef basic_string<wchar_t> wstring;
上述具体化又使用下面的具体化:
char_traits<char>
allocator<char>
char_traits<wchar_t>
allocator<wchar_t>
除char和wchar_t外,还可以通过定义traits类和使用basic_string模板来为其他一些类型创建一个string类。
13种类型和一个常量
basic_string模板定义了几种类型,供以后定义方法时使用:
typedef traits traits_type;
typedef typename traits::char_type value_type;
typedef Allocator allocator_type;
typedef typename Allocator::size_type size_type;
typedef typename Allocator::difference_type difference_type;
typedef typename Allocator::reference reference;
typedef typename Allocator::const_reference const_reference;
typedef typename Allocator::pointer pointer;
typedef typename Allocator::const_pointer const_pointer;
traits是一个将对应于某个具体类型(如char_traits<char>)的模板参数;traits_type将成为该具体类型的typedef。下述表示法:
typedef typename traits::char_type value_type;
意味着char_type是traits表示的类中定义的一个类型名。关键字typename告诉编译器:表达式traits::char_type是一种类型。例如,对于字符串具体化,value_type为char 。
size_type与size_of的用法相似,只是它根据存储的类型返回字符串的长度。对于string具体化,将根据char返回字符串的长度,在这种情况下,size_type与size_of等效。size_type是一种无符号类型。
difference_type用于度量字符串中两个元素之间的距离(单位为元素的长度)。通常,它是底层类型size_type有符号版本。
对于char具体化来说,pointer的类型为char * ,而reference的类型为char & 。不过,如果要为自己设计的类型创建具体化,则这些类型(pointer和reference)可以指向类,与基本指针和引用有相同的特征。
为将标准模板库(STL)算法用于字符串,该模板定义了一些迭代器类型:
typedef (models random access iterator) iterator;
typedef (models random access iterator) const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
该模板还定义了一个静态常量:
static const size_type npos = -1;
由于size_type是无符号的,因此将-1赋给npos相当于将最大的无符号值赋给它,这个值比可能的最大数组索引大1。
数据信息
下表列出了一些方法,他们的返回值可用来描述构造函数和其他方法的效果。其中大部分术语来自STL。
begin()、rend()、data()和c_str()它们都与字符串的第一个字符相关,但相关的方式不同。
begin()和rend()方法返回一个迭代器,这是一种广义指针。begin()返回一个正向迭代器模型,而rend()返回反转迭代器的一个副本。这两种方法都引用了string对象管理的字符串(由于string类使用动态内存分配,因此实际的string内容不一定位于对象中,因此,我们使用术语“管理”来描述对象和字符串之间的关系)。
可以将返回迭代器的方法用于基于迭代器的STL算法中。例如,使用STL reverse()函数来反转字符串的内容:
string word;
cin>>word;
reverse(word.begin(),word.end());
data()和c_str()方法返回常规指针。返回的指针将指向存储字符串字符的数组的第一个元素。该数组可能(但不一定)是string对象管理的字符串的副本(string对象采用的内部表示可以是数组,但不一定非得是数组)。由于返回的指针可能指向原始数据,而原始数据是const,因此不能用它们来修改数据。另外,当字符串被修改后,将不能保证这些指针是有效的,这表明它们可能指向原始数据。
c_str()指向的数组以空值字符(或与之等价的其他字符)结束。
data()只是确保实际的字符串是存在的。
因此,data()和size()可用作这种函数的参数,即指向数组元素的指针和表示要处理的元素数目的值:
string vampire("Do not stake me, oh my darling! ");
int vlad = byte_check(vampire.data(), vampire.size());
C++实现可能将string对象的字符串表示为动态分配的C-风格字符串,并使用char *指针来实现正向迭代器。这种情况下,实现可能让begin()、data()和c_str()都返回同样的指针,但返回指向3个不同的数据对象的引用也是合法的(虽然更复杂)。
6个构造函数和1个析构函数:
explicit basic_string(const Allocator & a = Allocator());
basic_string(const charT * s, const Allocator & a = Allocator());
basic_string(const basic_string & str, size_type pos = 0,size_type n = npos,
const Allocator & a = Allocator());
basic_string(const charT * s, size_type n,const Allocator & a = Allocator());
basic_string(size_type n, charT c, const Allocator & a = Allocator());
template<class InputIterator>
basic_string(InputIterator begin, InputIterator end,const Allocator & a = Allocator());
~basic_string();
其中每个构造函数都有参数: const Allocator & a = Allocator()
Allocator是用于管理内存的allocator类的模板参数名;Allocator()是这个类的默认构造函数。因此,默认情况下,构造函数将使用allocator对象的默认版本,但它们使得能够选择用allocator对象的其他版本。
默认构造函数原型如下:
explicit basic_string(const Allocator & a = Allocator());
通常,接受allocator类的默认参数,并使用构造函数来创建空字符串:
string bean;
wstring theory;
该构造函数被调用后,存在下面的关系:
(1) data()方法返回一个非空指针,可以将该指针加上0 。
(2) size()方法返回 0 。
(3) capacity()的返回值是不确定的。
将data()返回的值赋值给指针str后,第一个条件意味着str+0是有效的。
使用数组的构造函数
该方法让其能够将string对象初始化为一个C-风格字符串;从更普遍的意义来看,它使得能将charT具体化初始化为一个charT数组:
basic_string(const charT * s, const Allocator & a = Allocator());
为确定要复制的字符数,该构造函数将traits::length()方法用于s指向的数组(指针s不能为空值)。例如:
string toast("here's looking at you,kid. ");
使用指定的字符串来初始化toast对象。char类型的trsits::length()方法将使用空值字符来确定要复制多少个字符。
该构造函数被调用后,存在下面的关系:
(1) data()方法返回一个指针,该指针指向数组s的一个副本的第一个元素。
(2) size()方法返回的值等于trsits::length()的值。
(3) capacity()方法返回一个至少等于size()的值。
使用部分数组的构造函数
该方法让其能够使用C-风格字符串的一部分来初始化string对象;从更广泛的意义上说,使得能够使用charT数组的一部分来初始化charT具体化:
basic_string(const charT * s, size_type n,const Allocator & a = Allocator());
该构造函数将s指向的数组中的n个字符复制到构造的对象中。如果n大于s的长度,该方法将把字符串后面的内存内容解释为charT类型的数据。
该构造函数要求s不能是空值指针,同时n < npos(npos是一个静态类常量,它是字符串可能包含的最大元素数目)。如果n等于npos,将引发一个out_of_range异常(由于n的类型为size_type,而npos是size_type的最大值,因此n不能大于npos);否则,在该构造函数被调用后,存在下面的关系:
(1) data()方法返回一个指针,该指针指向数组s的一个副本的第一个元素。
(2) size()方法返回n 。
(3) capacity()方法返回一个至少等于size()的值。
复制构造函数
basic_string(const basic_string & str, size_type pos = 0,size_type n = npos,
const Allocator & a = Allocator());
调用复制构造函数时如果只提供一个basic_string参数,新对象将被初始化为该string参数:
string mel("i'm ok! ");
string ida(mel);
其中,ida将是mel管理的字符串副本。
参数pos指定了源字符串中的位置,将从这个位置开始进行复制:
string att("Telephone home.");
string et(att,4);
位置编号从0开始。et被初始化为"phone home" 。
参数n指定要复制的最大字符数目:
string att("Telephone home.");
string pt(att,4,5);
将pt初始化为字符串"phone"。
该构造函数不能跨越源字符串的结尾。因此,实际复制的字符数量等于n和str.size()-pos中较小的一个。
该构造函数要求pos不大于str.size(),就是说,被复制的初始位置必须位于元字符串中。否则将引发out_of_range异常。
该构造函数被调用后,copy_len将是n和str.size()-pos中较小的一个,并存在下面的关系:
(1) data()方法返回一个指向字符串str的指针,该字符串包含copy_len个元素,这些元素是从str的pos位置开始复制而得到的。
(2) size()方法返回copy_len。
(3) capacity()方法返回一个不小于size()的值。
使用一个字符的n个副本的构造函数
basic_string(size_type n, charT c, const Allocator & a = Allocator());
该构造函数要求n < npos ,否则将引发out_of_range异常。
该构造函数被调用后,将存在下面的关系:
(1) data()方法返回一个指向字符串第一个元素的指针,该字符串有n个元素组成,其中每个元素的值都为c 。
(2) size()方法返回n 。
(3) capacity()方法返回一个不小于size()的值。
使用区间的构造函数
该方法使用一个用迭代器定义的、STL-风格的区间:
template<class InputIterator>
basic_string(InputIterator begin, InputIterator end,const Allocator & a = Allocator());
begin迭代器指向源字符串中药复制的第一个元素,end指向要复制的最后一个元素的后面。
这种构造函数可用于数组、字符串或STL容器:
char cole[40] = "Old king Cole was a merry old soul.";
string title (cole+4,cole+8);
vector<char> input;
char ch;
while(cin.get(ch) && ch != '/n')
input.push_back(ch);
string str_input(input.begin(),input_end() );
上述第一种用法中,InputIterator的类型为const char * ;
在第二种用法中,InputIterator的类型为vector<char>::iterator 。
该构造函数被调用后,将存在下面的关系:
(1) data()方法返回一个指向字符串第一个元素的指针,该字符串是通过复制区间[begin, end)中的元素得到的。
(2) size()方法返回begin到end之间的距离(度量距离时,使用的单位为迭代器解除引用得到的数据类型的长度)。
(3) capacity()方法返回一个不小于size()的值。
内存相关
下图列出了一些与内存相关的方法