string类:
string类由头文件string支持(头文件string.h和cstring支持对C-风格字符串进行操纵的C库字符串函数)。
- string的构造函数:
string(const char* s) 将string对象初始化为s指向的NBTS(C风格字符串) string(size_type n,char c) 将string对象初始化为包含n个字符c string(const string & str) 复制构造函数:将string对象初始化为string对象str string() 默认构造函数:创建默认的string对象,长度为0 string(const char* s,size_type n) 将string对象初始化为s指向的NBTS的前n个字符 -
string类的输入和C-风格字符串的输入:
string类的输入 | C-风格字符串的输入 |
string lname; cin >> lname; #1 getline(cin,lname); #2 | char info[10]; cin >> info; #1 cin.getline(info,10); #2 |
string版本的getline()将自动调整目标string对象的大小,使之刚好能够存储输入的字符。
它们的区别:读取C-风格字符串的函数getline()是istream类的方法,而string版本中getline()是独立的函数。这就是对于C- 风格字符串输入,cin是调用对象;而对于string对象输入,cin是函数参数的原因。
3.string类的其他方法:
string类对全部6个关系运算符都进行了重载;对每个关系运算符,都以三种方式被重载:
operator<(const string &,const string &); operator==(const string &,const char *); operator!=(const char *,const string &).
size()和length()成员函数都返回字符串中字符数;
find()方法:
当创建字符串对象时会为其分配内存块,如果字符串不断增大,超过了内存块大小,程序将分配一个大小为原来两倍的新 内存块。方法capacity()返回当前分配给字符串的内存块的大小;reserve()方法请求内存块的最小长度。
STL:
- STL组成部分:容器(containers)、迭代器(iterators)、空间配置器(allocator)、配接器(adapters)、算法(algorithms)、仿函数(functors)六个部分。其设计都是基于泛型编程的原则。
- STL被组织为下面的13个头文件:<algorithm>、<deque>、<functional>、<iterator>、<vector>、<list>、<map>、<memory>、<numeric>、<queue>、<set>、<stack>和<utility>。
- 容器(containers)存储的值类型相同。头文件主要有:<vector>,<list>,<deque>,<set>,<map>,<stack>和<queue>组成。
- 迭代器(iterators)遍历容器的对象,与能够遍历数组的指针类似,是广义指针。头文件主要有:<utility>,<iterator>和<memory>组成。
- 算法(algorithms)完成特定任务(如对数组进行排序或在链表中查找特定的值)。头文件主要有:<algorithm>,<numeric>和<functional>组成。<algorithm>是所有STL头文件中最大的一个(然而它很好理解),它是由一大堆模版函数组成的,可以认为每个函数在很大程度上都是独立的,其中常用到的功能范围涉及到比较、交换、查找、遍历操作、复制、修改、移除、反转、排序、合并等等。
initializer_list:其头文件为initializer_list
- 这个模板类包含成员函数begin()和end()来访问列表元素、成员函数size()返回元素数。
- initializer_list类的初衷旨在将一系列值传递给构造函数(容器类构造函数)或其他函数(自定义函数)。
- initializer_list的迭代器类型为const,固不能修改initializer_list中的值;但可以将一个initializer_list赋给另一个initializer_list。 std::initializer_list<double>d = {1.1,2.2,3.3}; d = {4.4,5.5,6.6};
- 函数参数可以是initializer_list字面量,也可以是initializer_list变量。
double sum(std::initializer_list<double>l1); double average(const std::initializer_list<double> &l2);
智能指针(auto_ptr(C++98提供的解决方案)、unique_ptr、shared_ptr、weak_ptr)
- 智能指针是行为类似于指针的类对象,但这种对象还有其他的功能。其头文件为memory。
- 智能指针模板使得管理由new分配的内存更容易。
- 智能指针的思想:当程序终止时,本地变量将从栈内存中删除——因此常规指针占据的内存将被释放,但是常规指针指向的内存不会被释放。而智能指针是类对象,则可以在对象过期时,让它的析构函数删除指向的内存。
常规指针 | auto_ptr |
void demo1(){ double *pd = new double; #为pd和一个double值分配存储 空间,保存地址 *pd = 25.5; #将值复制到动态内存中; return; #删除pd,值被保存在动态内存中 } | void demo2(){ auto_ptr<double> ap(new double); #为ap和一个double值分配存储 空间,保存地址 *ap = 25.5; #将值复制到动态内存中; return; #删除ap,ap的析构函数释放动态内存。 } |
错误示例:
auto_ptr<string> ps (new string("I reigned lonely as a cloud.")); auto_ptr<string> vocation; vocation = ps; |
若ps和vocation是常规指针,则两个指针将指向同一个string对象。这是不能接受的,因为程序将试图删除同一个对象两次——一次是ps过期时,另一次是vovation过期时。避免这种情况的方法。
定义赋值运算符,使之执行深复制。 | 这样两个指针指向不同对象,其中一个对象是另一个对象的副本。 |
建立所有权概念(auto_ptr和unique_ptr) | 对于特定的对象,只能有一个智能指针可拥有它,这样只有拥有对象的智能指针的构造函数会删除该对象。然后,让赋值操作转让所有权。 |
创建智能更高的指针,跟踪引用特定对象的智能指针数这称为引用计数(shared_ptr) | 如:赋值时,计数将加1,而指针过期时,计数将减1.仅当最后一个指针过期时,才调用delete。 |
- 在赋值操作时,auto_ptr可能在程序运行阶段崩溃;而unique_ptr则在编译器因赋值语句出现错误。
auto_ptr<string> p1(new string("auto")); #1
auto_ptr<string> p2; #2
p2 = p1; #3
unique_ptr<string> p3(new string("auto")); #4
unique_ptr<string> p4; #5
p4 = p3; #6
语句3中,p2接管string对象的所有权,p1的所有权被剥夺,这可以防止p1和p2的析构函数试图删除同一个对象;但是如果程序随后试图使用p1,因p1不再指向有效数据而出错。 编译器认为语句6非法,避免了p3不再指向有效数据的问题。因此,unique_ptr比auto_ptr更安全(编译阶段错误比潜在的程序崩溃更安全)。
- 解决智能指针赋值后多个指针指向同一对象的问题:
using namespace std; unique_ptr<string> pu1(new string "Hi ho!"); unique_ptr<string> pu2; pu2 = pu1; //#1 not allowed unique_ptr<string>pu3; pu3 = unique_ptr<string>(new string "Yo!"); //#2 allowed
pu2 = move(pu1); //#3
std::unique_ptr<double[]>p (new double(5)) //will use delete[] |
|