《C++ Primer Plus》(第6版)中文版—学习笔记—string类和标准模板库

第16章 string类和标准模板库

string类

构造字符串

string类的构造函数,NBTS——传统的C字符串

构造函数 描述
string(const char * s) 将string对象初始化为s指向的NBTS
string(size_type n, char c) 创建一个包含n个元素的string对象,其中每个元素都被初始化为字符c
string(const string & str) 将一个string对象初始化为string对象str(复制构造函数)
string() 创建一个默认的string对象,长度为0(默认构造函数)
string(const char * s, size_type n) 将string对象初始化为s指向的NBTS的前n个字符,即使超过了NBTS的结尾
template<class Iter> " 换行 " string(Iter begin, Iter end) 将string对象初始化为区间[begin, end)内的字符,其中begin和end的行为就像指针,用于指定位置,范围包括begin在内,但不包括end
string(const string & str, string size_type pos = 0, size_type n = pos) 将一个string对象初始化为对象str中从位置pos开始到结尾的字符,或从位置pos开始的n个字符
string(string && str) noexcept 这是C++11新增的,它将一个string对象初始化为string对象str,并可能修改str(移动构造函数)
string(initializer_list<char> il) 这是C++11新增的,它将一个string对象初始化为初始化列表il中的字符
// 这是上述其中第6个构造函数,除最后两个,其他的很好理解
/*
begin和end就像指针那样,指向内存中两个位置(通常,begin和end可以使迭代器——广泛用于STL中的广义化指针)。但区间为[begin,end),也就是说不包括最后的end指向的位置。
*/
template<class Iter>
string(Iter begin, Iter end)
// 请看下面的用法
char alls[] = "All's well that ends well";
string five(alls, 20);
string six(alls+6, alls+10);
string seven(&five[6], &five[10]);
// 其中最后两句用的就是第六个构造函数
// string six(alls+6, alls+10);	可以看到alls+6,alls+10的类型都是char *,因为使用模板时,将用类型char *代替Iter。
// 再来看看&five[6],因为five[6]是一个char类型,使用&就是去char的地址,所以&five[6]也就是char类型

最后的两个构造函数是c++11新增的。

string输入

对于c风格字符串,有3中方式输入

char info[100];
cin >> info;				// read a word
cin.getline(info, 100);		// read a line, discard \n
// cin.getline(info, 100, ':');
cin.get(info, 100);			// read a line, leave \n in queue

string的输入方式有

string stuff;
cin >> stuff;
getline(stuff, ":");	// 将会读取到":"字符,但会舍弃":"字符

string类可以自动调整字符串的大小,不用想c-风格字符串一样预先设定大小。

c-风格字符串和string类在设计上面的一个区别就是,对于c-风格字符串输入,cin是调用对象,而对于string对象输入,cin是一个函数参数的原因。

cin.operator>>(fname);
operator>>(cin, lname);

使用字符串

string还提供了哪些功能

字符串种类

智能指针模板类

  • auto_ptr
  • unique_ptr
  • shared_ptr

这三个智能指针模板都定义了类似指针的对象,可以将new获得的地址赋给这些对象。当之智能指针过期时,其析构函数将使用delete来释放内存。需包含头文件memory

shared_ptr<double> pd;
double *p_reg = new double;
pd = p_reg;									// not allowed (implicit conversion)
pd = shared_ptr<double>(p_reg);				// allowed (explicit conversion)
shared_ptr<double> pshared = p_reg;			// not allowed (implicit conversion)
shared_ptr<double> pshared(p_reg);			// allowed (explicit conversion)

auto_ptr将被摒弃

auto_ptr<string> ps (new string("I reigned lonely as a cloud."));
auto_ptr<string> vocation;
vocation = ps;

如果ps和vocation是常规指针,则两个指针都指向一个string对象。这是不能接受的,因为程序将试图删除一个对象两次。

要避免这种问题,方法有多种

  • 定义赋值运算符,执行深复制
  • 建立所有权,一个对象只能有一个指针指向他
  • 创建智能更高的指针,跟踪引用特定对象的智能指针数

unique_ptr和auto_ptr

auto_ptr<string> p1(new string("auto"));
auto_ptr<string> p2;
p2 = p1;

unique_ptr<string> p3(new string("auto"));
unique_ptr<string> p4;
p4 = p3;

当使用auto_ptr时,第一段代码可以使用,但是会留下隐患,但是使用unique_ptr时,第二段代码将在编译阶段报错,编译器不允许将p3赋值给p4。

auto_ptr,当p1赋给p2之后,p1将会变为空指针,所以当我们需要使用p1的时候就会出现错误,这是编译器不会报错。

虽然unique_ptr禁止了赋值操作,但是对于临时的智能指针却能允许,比如

unique_ptr<string> demo(const char * s)
{
    
    
	unique_ptr<string> temp(new string(s));
	return temp;
}

上面的代码允许了智能指针的临时赋值,也是说程序试图将一个unique_ptr赋给另一个时,如果源unique_ptr是个临时右值,编译器允许这样做;如果源unique_ptr将存在一段时间,编译器将禁止这样做。

使用new分配内存时,才能使用auto_ptr和shared_ptr,使用new[]分配内存时,不能使用它们。不使用new分配内存时,不能使用auto_ptr或shared_ptr;不使用new或new[]分配内存时,不能使用unique_ptr。

细看《STL源码剖析》

猜你喜欢

转载自blog.csdn.net/weixin_49643423/article/details/114269050