头文件:
#inlcude <string>
下表有string的7个构造函数及C++11新增的2个构造函数;
一,下例是几种string的应用:
#include <iostream>
#include <string>
int main()
{
using namespace std;
string one("Lottery Winner!");
cout << one << endl; // Lottery Winner!
string two(20, '$');
cout << two << endl; // $$$$$$$$$$$$$$$$$$$$
string three(one);
cout << three <<endl; // Lottery Winner!
one += " Oops!";
cout << one << endl; // Lottery Winner Oops!
two = "Sorry! That was ";
three[0] = 'P';
string four = two + three;
cout << four << endl; // Sorry! That was Pottery Winner!
char alls[] = "All's well that ends well";
string five(alls, 20);
cout << five << "!\n"; // All's well that ends!
string six(alls + 6, alls + 10); // 从alls的第6个位置截止至alls的第10个位置
cout << six << ", "; // well,
string seven(&five[6], &five[10]); //同上
cout << seven << "...\n"; // well...
string eight(four, 7, 16); // 意思是从four的第7个位置开始数16个放进eight
cout << eight << " in motion!" << endl; // That was Pottery in motion!
return 0;
}
要注意的是:
template<class Type> string(Iter begin, Iter end);
这里[begin, end) 意味着 包括 begin, 不包括 end,如上例中的 six, seven
二,C++新增的构造函数
移动构造函数move constructor的运行原理如下图,在有些情况下,编译器可使用它而不是复制构造函数来优化性能。
用法:string(string && str)
例:
A(A && h) : a(h.a)
{
h.a = nullptr; //还记得nullptr?
}
可以看到,这个构造函数的参数不同,有两个&操作符, 移动构造函数接收的是“右值引用”的参数。
还要来说一下,这里h.a置为空,如果不这样做,h.a在移动构造函数结束时候执行析构函数会将我们偷来的内存析构掉。h.a会变成悬垂指针。
这里要注意的是,异常发生的情况,要尽量保证移动构造函数不发生异常,可以通过noexcept关键字,这样可以保证移动构造函数中抛出来的异常会直接调用terminate终止程序。
在c++11中,右值引用就是对一个右值进行引用的类型,右值通常不具有名字,我们就只能通过引用的方式找到它的存在了。
比较一下下面两条语句:
T &&a = returna();
T b = returnb();
此时a是右值引用,他比b少了一次对象析构和对象构造的过程。a直接绑定了returna返回的临时变量。b只是由临时变量值构造而成的。
右值引用就是让返回的右值(临时对象)重获新生,延长生命周期。临时对象析构了,但是右值引用存活。
不过要注意的是,右值引用不能绑定左值:int a; int &&c = a; 这样是不行的。
这里有一个函数就是 move函数,它能够将左值强制转换成右值引用。
A & operator = (A&& h)
{
assert(this != &h);
a = nullptr;
a = move(h.a);
h.a = nullptr;
return *this;
}
构造函数 string(initializer_list<char> il) 可以将列表初始化用于string类
例:
string a = {'L', 'i', 's', 't'};
就string类而说,用处不大,因为使用C-风格字符串更容易。
三,关于string类的输入。
对于C-风格字符串,有三种输入方式:
char info[100];
cin >> info; //#1
cin.getline(info, 100); // #2 discard \n
cin.get(info, 100); // #3 leave \n in queue
对于string对象,有两种输入方式:
string stuff;
cin >> stuff;
getline(cin, stuff); // discard \n
getline()有一个可选参数,用以确定输入的边界:
但注意的是:指定分界符后,换行符将视为常规字符。
cin.getline(info, 100, ':'); //C-风格字符串
getline(stuff, ':'); // string
使用区别:string版的getline()将自动调整目标string 对象的大小,使之刚好能够存储输入的字符,但也不是无限的,
第一个限制是string对象的最大允许长度,由常量string::npos指定,这通常是最大的unsigned int 值。
设计区别:C-风格字符串,cin是调用对象;对string对象,cin是一个函数参数。
string版本的getline()函数从输入中读取字符,并将其存储目标string中,以下三种情况会终止:
1)到达文件尾
2)遇到分界字符(默认\n)
3)读取的字符数达到最大允许值(string::npos 与 可供分配的内存字节数中较小的一个)
string字符串的比较:
string snake1("cobra");
string snake2("coral");
char snake3[20] = "anaconda";
if (snake1 < snake2) // operator<(const string& , const string& )
...
if (snake1 == snake3) // operator==(const string& , const char* )
...
if (snake3 != snake2) // operator!=(const char* , const string& )
string字符串的长度:
if (snake1.length() == snake2.size())
...
lengh()来自较早的string类,而size()则是为STL兼容性而添加的。