头文件:

#inlcude <string>

下表有string的7个构造函数及C++11新增的2个构造函数;


C++:C++的string类的构造函数及对象之间的比较_右值引用

一,下例是几种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)

C++:C++的string类的构造函数及对象之间的比较_C++_02

例:

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兼容性而添加的。