20. C++11新特性和高级特性

20.1 C++11新特性

1)统一的初始化方法:使用{ }初始化数组和容器

int arr[3]{1, 2, 3};
vector<int> iv{1, 2, 3};
map<int, string> mp{{1, "a"}, {2, "b"}};
string str{"Hello World"};
int * p = new int[20]{1,2,3};
struct A {
	int i,j; A(int m,int n):i(m),j(n) { }
};
A func(int m,int n ) { return {m,n}; }
int main() { A * pa = new A {3,7}; }

2)成员变量默认初始值:在定义类的时候可以初始化变量

class B
{
public:
	int m = 1234;
	int n;
};
int main(){
	B b;
	cout << b.m << endl; //输出 1234
	return 0;
}

3)auto关键字:用于定义变量,编译时可以自动判断变量的类型

auto i = 100; // i 是 int
auto p = new A(); // p 是 A *
auto k = 34343LL; // k 是 long long
map<string,int,greater<string> > mp;
for( auto i = mp.begin(); i != mp.end(); ++i)
	cout << i->first << "," << i->second ;
//i的类型是: map<string,int,greater<string> >::iterator
class A { };
A operator + ( int n,const A & a){
	return a;
}
template <class T1, class T2>
auto add(T1 x, T2 y) -> decltype(x + y) {
	return x+y;
}
auto d = add(100,1.5); // d是double d=101.5
auto k = add(100,A()); // d是A类型

4)decltype 关键字:求表达式的类型

int i;
double t;
struct A { double x; };
const A* a = new A();
decltype(a) x1; // x1 is A *
decltype(i) x2; // x2 is int
decltype(a->x) x3; // x3 is double
decltype((a->x)) x4 = t; // x4 is double&
//在里面多用一个括号会被判定为引用

5)智能指针shared_ptr

(1)头文件: <memory>
(2)通过shared_ptr的构造函数,可以让shared_ptr对象托管一个new运算符返回的指针,写法如下:

shared_ptr<T> ptr(new T); // T 可以是 int ,char, 类名等各种类型

(3)此后ptr就可以像 T* 类型的指针一样来使用,即 *ptr 就是用new动态分配的那个对象,而且不必操心释放内存的事。
(4)多个shared_ptr对象可以同时托管一个指针,系统会维护一个托管计数。当无shared_ptr托管该指针时,delete该指针。
(5)shared_ptr对象不能托管指向动态分配的数组的指针,否则程序运行会出错

shared_ptr<T> ptr(new T[100]);	//error

(6)示例1:

#include <memory>
#include <iostream>
using namespace std;
struct A {
	int n;
	A(int v = 0):n(v){ }
	~A() { cout << n << " destructor" << endl; }
};
int main(){
	shared_ptr<A> sp1(new A(2)); //sp1托管A(2)
	shared_ptr<A> sp2(sp1); 	//sp2也托管 A(2)
	cout << "1)" << sp1->n << "," << sp2->n << endl;//输出1)2,2
	shared_ptr<A> sp3;
	A * p = sp1.get(); 	//p 指向 A(2),返回指针
	cout << "2)" << p->n << endl;
	sp3 = sp1; //sp3也托管 A(2)
	cout << "3)" << (*sp3).n << endl; //输出 2
	sp1.reset(); //sp1放弃托管 A(2)
	if( !sp1 )	//sp1没有托管任何东西
		cout << "4)sp1 is null" << endl; //会输出
	A * q = new A(3);
	sp1.reset(q); // sp1托管q
	cout << "5)" << sp1->n << endl; //输出 3
	shared_ptr<A> sp4(sp1); //sp4托管A(3)
	shared_ptr<A> sp5;
	sp1.reset(); //sp1放弃托管 A(3)
	cout << "before end main" <<endl;
	sp4.reset(); //sp1放弃托管 A(3)
	cout << "end main" << endl;
	return 0; //程序结束,会delete 掉A(2)
}

(7)示例2:不增加托管计数情况:

#include <iostream>
#include <memory>
using namespace std;
struct A{
	~A() { cout << "~A" << endl; }
};
int main(){
	A * p = new A();
	shared_ptr<A> ptr(p);
	shared_ptr<A> ptr2;
	ptr2.reset(p); 		//并不增加 ptr中对p的托管计数
	cout << "end" << endl;
	return 0;
}

(8)unique_ptr:独享指针
a)只能有一个unique_ptr托管某个对象
b)可以用move更换托管对象
c)使用方法:

unique_ptr<T> p1(new T);
unique_ptr<T> p2(p1);	//error
unique_ptr<T> p3 = std::move(p1);	//ok

d)unique_ptr和shared_ptr相比,可以指向数组:

unique_ptr<int> p(new int[10]);	//ok
p[4]  = 5;	//ok

(9)weak_ptr:shared_ptr的助手:
a)weak_ptr是用来监视shared_ptr的,不会增加引用计数,没有*和->运算符,纯粹只是作为旁观者监视shared_ptr
b)基本用法:

shared_ptr<int> p1(new int(10));
weak_ptr<int> p2(p1);
cout << p2.use_count() << endl;	//输出1
//使用expired()成员函数判断是否监视有效
if (p2.expired())
	cout << "weak_ptr无效,所监视的智能指针已经失效"<< endl;
else
	cout << "weak_ptr有效"<< endl;

//使用lock()方法获取所监视的shared_ptr
auto p3 = p2.lock();
cout << * p3 << endl;	//输出10

6)空指针nullptr

#include <memory>
#include <iostream>
using namespace std;
int main() {
	int* p1 = NULL;
	int* p2 = nullptr;
	shared_ptr<double> p3 = nullptr;
	if(p1 == p2)
	cout << "equal 1" <<endl;
	if( p3 == nullptr)
	cout << "equal 2" <<endl;
	if( p3 == p2) ; // error
	if( p3 == NULL)
	cout << "equal 4" <<endl;
	bool b = nullptr; // b = false
	int i = nullptr; //error,nullptr不能自动转换成整型
	return 0;
}
去掉出错的语句后输出:
equal 1
equal 2
equal 4

7)基于范围的for循环:

#include <iostream>
#include <vector>
using namespace std;
struct A { int n; A(int i):n(i) { } };
int main() {
	int ary[] = {1,2,3,4,5};
	for(int & e: ary)
		e*= 10;
	for(int e : ary)
		cout << e << ",";
	cout << endl;
	vector<A> st(ary,ary+5);
	for( auto & it: st)
		it.n *= 10;
	for( A it: st)
		cout << it.n << ",";
	return 0;
}
输出:
10,20,30,40,50,
100,200,300,400,500,

8)右值引用和move语义

(1)右值:一般来说,不能取地址的表达式,就是右值,能取地址的,就是左值

class A { };
A & r = A(); // error , A()是无名变量,是右值
A && r = A(); //ok, r 是右值引用

(2)主要目的是提高程序运行的效率,减少需要进行深拷贝的对象进行深拷贝的次数
(3)以前学的都是左值引用(引用变量),右值引用就是引用常量和临时对象,可以延长变量的生命周期,和右值引用变量一起消亡
(4)std::move(a)等价于 static_cast<T&&>(a),就是将变量a转化成右值引用
(5)示例:

#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class String{
public:
	char * str;
	String():str(new char[1]) { str[0] = 0;}
	String(const char * s) {
		str = new char[strlen(s)+1];
		strcpy(str,s);
	}
	String(const String & s) {
		cout << "copy constructor called" << endl;
		str = new char[strlen(s.str)+1];
		strcpy(str,s.str);
	}
	String & operator=(const String & s) {
		cout << "copy operator= called" << endl;
		if( str != s.str) {
			delete [] str;
			str = new char[strlen(s.str)+1];
			strcpy(str,s.str);
		}
		return * this;
	}
	String(String && s):str(s.str) {
		cout << "move constructor called"<<endl;
		s.str = new char[1];
		s.str[0] = 0;
	}
	// move assigment
	String & operator = (String &&s) {
		cout << "move operator= called"<<endl;
		if (str!= s.str) {
			delete [] str;
			str = s.str;
			s.str = new char[1];
			s.str[0] = 0;
		}
		return *this;
	}
	~String() { delete [] str; }
};
template <class T>
void MoveSwap(T& a, T& b) {
	T tmp(move(a)); // std::move(a)为右值,这里会调用move constructor
	a = move(b); // move(b)为右值,因此这里会调用move assigment
	b = move(tmp); // move(tmp)为右值,因此这里会调用move assigment
}
int main()
{
	//String & r = String("this"); // error
	String s;
	s = String("ok"); // String("ok")是右值
	cout << "******" << endl;
	String && r = String("this");
	cout << r.str << endl;
	String s1 = "hello",s2 = "world";
	MoveSwap(s1,s2);
	cout << s2.str << endl;
	return 0;
}

9)无序容器(哈希表):

(1)哈希表插入和查询的时间复杂度几乎是常数
(2)用法和map相同
(3)示例:根据姓名查询获奖时间

#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
int main(){
	unordered_map<string,int> turingWinner; //图灵奖获奖名单
	turingWinner.insert(make_pair("Dijkstra",1972));
	turingWinner.insert(make_pair("Scott",1976));
	turingWinner.insert(make_pair("Wilkes",1967));
	turingWinner.insert(make_pair("Hamming",1968));
	turingWinner["Ritchie"] = 1983;
	string name;
	cin >> name; //输入姓名
	unordered_map<string,int>::iterator p =
	turingWinner.find(name);
	//据姓名查获奖时间
	if( p != turingWinner.end())
	cout << p->second;
	else
	cout << "Not Found" << endl;
	return 0;
}

10)正则表达式(就是某种模式的字符串)

#include <iostream>
#include <regex> //使用正则表达式须包含此文件
using namespace std;
int main(){
	regex reg("b.?p.*k");
	cout << regex_match("bopggk",reg) <<endl; //输出 1, 表示匹配成功
	cout << regex_match("boopgggk",reg) <<endl; //输出 0, 匹配失败
	cout << regex_match("b pk",reg) <<endl ; //输出 1, 表示匹配成功
	regex reg2("\\d{3}([a-zA-Z]+).(\\d{2}|N/A)\\s\\1");
	string correct="123Hello N/A Hello";
	string incorrect="123Hello 12 hello";
	cout << regex_match(correct,reg2) <<endl; //输出 1,匹配成功
	cout << regex_match(incorrect,reg2) << endl; //输出 0, 失败
}

11)Lambda表达式

(1)只使用一次的函数对象,能否不要专门为其编写一个类?
(2)只调用一次的简单函数,能否在调用时才写出其函数体?
(3)形式:

[外部变量访问方式说明符](参数表) ->返回值类型{
	语句组
}

a)[ ] 不使用任何外部变量
b)[=] 以传值的形式使用所有外部变量
c)[&] 以引用形式使用所有外部变量
d)[x, &y] x 以传值形式使用,y 以引用形式使用
e)[=,&x,&y] x,y 以引用形式使用,其余变量以传值形式使用
f)[&,x,y] x,y 以传值的形式使用,其余变量以引用形式使用
g)“->返回值类型”也可以没有, 没有则编译器自动判断返回值类型。
h)如果传值进去就不能改变该变量,否则会报错
(4)示例1:lambda表达式基本使用

int main(){
	int x = 100,y=200,z=300;
	cout << [ ](double a,double b) { return a + b; }(1.2,2.5)
	<< endl;
	//lambda表达式定义,y和z以引用传进去,x以值传进去
	auto ff = [=,&y,&z](int n) {
		cout <<x << endl;
		y++; z++;
		return n*n;
	};
	//lambda表达式使用
	cout << ff(15) << endl;
	cout << y << "," << z << endl;
}
输出:
3.7
100
225
201,301

(5)示例2:

int a[4] = { 4,2,11,33};
sort(a,a+4,[ ](int x,int y)->bool {return x%10 < y%10; });
for_each(a,a+4,[ ](int x) {cout << x << " " ;} ) ;

(6)示例3:

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main(){
	vector<int> a { 1,2,3,4};
	int total = 0;
	//把total使用引用传进来
	for_each(a.begin(),a.end(),[&](int & x){total += x; x*=2;});
	cout << total << endl; //输出 10
	for_each(a.begin(),a.end(),[ ](int x){ cout << x << " ";});
	return 0;
}

12)chrono时间库

(1)chrono 库主要包含了三种类型:时间间隔 Duration、时钟 Clocks 和时间点 Time point
(2)标准库为了方便使用,就定义了一些常用的时间间隔,如时、分、秒、毫秒、微秒和纳秒,在chrono命名空间下,它们的定义如下:

typedef duration <Rep, ratio<3600,1>> hours;

typedef duration <Rep, ratio<60,1>> minutes;

typedef duration <Rep, ratio<1,1>> seconds;

typedef duration <Rep, ratio<1,1000>> milliseconds;

typedef duration <Rep, ratio<1,1000000>> microseconds;

typedef duration <Rep, ratio<1,1000000000>> nanoseconds;

(3)通过定义这些常用的时间间隔类型,我们能方便的使用它们,比如线程的休眠:

std::this_thread::sleep_for(std::chrono::seconds(3)); //休眠三秒
std::this_thread::sleep_for(std::chrono:: milliseconds (100)); //休眠100毫秒

(4)chrono 还提供了获取时间间隔的时钟周期个数的方法 count()

#include <iostream>
#include <chrono>
using namespace std;
int main(void) {
    std::chrono::milliseconds ms{3};//3毫秒
    std::chrono::microseconds us = 2 * ms;//6000微秒
    std::chrono::duration<double, std::ratio<1, 30>> hz(3.5);
    //hz为3.5个周期时间长度,每个周期为1/30s
    cout << ms.count() << endl;//3 一个周期为1s
    cout << us.count() << endl;//6000 一个周期为1us
    cout << hz.count() << endl;//3.5
    return 0;
}

(5)时间间隔之间可以做运算,比如下面的例子中计算两端时间间隔的差值:

#include <iostream>
#include <chrono>
using namespace std;
int main(void) {
    std::chrono::minutes t1(10);//10分钟
    std::chrono::seconds t2( 60 );//60秒
    std::chrono::seconds t3 = t1 - t2;
    //t3 的时间周期为 second
    std::cout << t3.count() << " second" << std::endl;
    //通过 duration_cast 将时间周期转化为 minutes
    cout << chrono::duration_cast<chrono::minutes>(t3).count() << " minutes" << endl;
    return 0;
}
// 输出:
// 540 second
// 9 minutes

(6)使用chrono中的steady_clock计算程序运行时间(相当于秒表)

chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
//测试程序	
chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
cout << "time spend: " << time_used.count() << " seconds." << endl;
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;
int main() {

    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
    //测试程序
    chrono::seconds  time(1);
    this_thread::sleep_for(time);

    chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
    chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
    cout << "time spend: " << time_used.count() << " seconds." << endl;	//输出1.00004
}

20.2 强制类型转换

20.2.1 static_cast

1)用于基本数据类型之间的转换,比如整型和实数型、字符型之间互相转换,static_cast不能来在不同类型的指针之间互相转换,也不能用于整型和指针之间的互相转换,也不能用于不同类型的引用之间的转换。
2)static_cast示例:

#include <iostream>
using namespace std;
class A{
public:
	operator int() { return 1; }
	operator char * (){ return NULL; }
};
int main(){
	A a;
	int n; char * p = "New Dragon Inn";
	n = static_cast<int>(3.14); // n 的值变为 3
	n = static_cast<int>(a); //调用a.operator int, n的值变为 1
	p = static_cast<char*>(a);//调用a.operator int *,p的值变为 NULL
	n = static_cast<int> (p);//编译错误,static_cast不能将指针转换成整型
	p = static_cast<char*>(n);//编译错误,static_cast不能将整型转换成指针
	return 0;
}

20.2.2 reinterpret_cast

1)用来进行各种不同类型的指针之间的转换、不同类型的引用之间转换、以及指针和能容纳得下指针的整数类型之间的转换。转换的时候,执行的是逐个比特拷贝的操作,操作有很大风险
2)reinterpret_cast示例:

#include <iostream>
using namespace std;
class A{
public:
	int i;
	int j;
	A(int n):i(n),j(n) { }
};
int main(){
	A a(100);
	int & r = reinterpret_cast<int&>(a); //强行让 r 引用 a,引用a的前四个字节
	r = 200; //把 a.i 变成了 200
	cout << a.i << "," << a.j << endl; // 输出 200,100
	int n = 300;
	A * pa = reinterpret_cast<A*> ( & n); //强行让 pa 指向 n
	pa->i = 400; // n 变成 400
	pa->j = 500; //此条语句不安全,很可能导致程序崩溃
	cout << n << endl; // 输出 400
	long long la = 0x12345678abcdLL;
	pa = reinterpret_cast<A*>(la);
	// la太长,只取低32位0x5678abcd拷贝给pa
	unsigned int u = reinterpret_cast<unsigned int>(pa);
	//pa逐个比特拷贝到u
	cout << hex << u << endl; //输出 5678abcd
	typedef void (* PF1) (int);
	typedef int (* PF2) (int,char *);
	PF1 pf1; PF2 pf2;
	pf2 = reinterpret_cast<PF2>(pf1);
	//两个不同类型的函数指针之间可以互相转换
}

20.2.3 const_cast:

(1)用来进行去除const属性的转换。将const引用转换成同类型的非const引用,将const指针转换为同类型的非const指针时用它
(2)例如:

const string s = “Inception”;
string & p = const_cast<string&>(s);
string * ps = const_cast<string*>(&s);
// &s的类型是const string *

20.2.4 dynamic_cast

(1)专门用于将多态基类的指针或引用,强制转换为派生类的指针或引用,而且能够检查转换的安全性。对于不安全的指针转换,转换结果返回NULL指针。
(2)dynamic_cast不能用于将非多态基类的指针或引用,强制转换为派生类的指针或引用
(3)示例:

#include <iostream>
#include <string>
using namespace std;
class Base{ //有虚函数,因此是多态基类
public:
	virtual ~Base() { }
};
class Derived:public Base { };
int main(){
	Base b;
	Derived d;
	Derived * pd;
	pd = reinterpret_cast<Derived*> ( &b);
	if( pd == NULL)
		//此处pd不会为NULL。reinterpret_cast不检查安全性,总是进行转换
		cout << "unsafe reinterpret_cast" << endl; //不会执行
	pd = dynamic_cast<Derived*> ( &b);
		if( pd == NULL)
		//结果会是NULL,因为 &b不是指向派生类对象,此转换不安全
		cout << "unsafe dynamic_cast1" << endl; //会执行
	pd = dynamic_cast<Derived*> ( &d); //安全的转换
	if( pd == NULL) //此处pd 不会为NULL
		cout << "unsafe dynamic_cast2" << endl; //不会执行
	return 0;
}

20.3 异常处理

1)程序运行中总难免发生错误
(1)数组元素的下标超界、访问NULL指针
(2)除数为0
(3)动态内存分配new需要的存储空间太大
2)C++ 通过 throw 语句和 try…catch 语句实现对异常的处理。throw 语句的语法如下:

throw  表达式;

(1)该语句拋出一个异常。异常是一个表达式,其值的类型可以是基本类型,也可以是类。
(2)try…catch 语句的语法如下:

try {
    语句组
}
catch(异常类型) {
    异常处理代码
}
...
catch(异常类型) {
    异常处理代码
}

(3)catch 可以有多个,但至少要有一个
(4)不妨把 try 和其后{}中的内容称作“try块”,把 catch 和其后{}中的内容称作“catch块”
(5)try…catch 语句的执行过程是:执行 try 块中的语句,如果执行的过程中没有异常拋出,那么执行完后就执行最后一个 catch 块后面的语句,所有 catch 块中的语句都不会被执行;如果 try 块执行的过程中拋出了异常,那么拋出异常后立即跳转到第一个“异常类型”和拋出的异常类型匹配的 catch 块中执行(称作异常被该 catch 块“捕获”),执行完后再跳转到最后一个 catch 块后面继续执行
(6)示例:

#include <iostream>
using namespace std;
int main(){
    double m ,n;
    cin >> m >> n;
    try {
        cout << "before dividing." << endl;
        if( n == 0)
            throw -1; //抛出int类型异常
        else
            cout << m / n << endl;
        cout << "after dividing." << endl;
    }
    catch(double d) {
        cout << "catch(double) " << d <<  endl;
    }
    catch(int e) {
        cout << "catch(int) " << e << endl;
    }
    cout << "finished" << endl;
    return 0;
}
程序的运行结果如下:
9 6↙
before dividing.
1.5
after dividing.
finished

9 0↙
before dividing.
catch(int) -1
finished

(7)当 n 为 0 时,try 块中会拋出一个整型异常。拋出异常后,try 块立即停止执行。该整型异常会被类型匹配的第一个 catch 块捕获,即进入catch(int e)块执行,该 catch 块执行完毕后,程序继续往后执行,直到正常结束
(8)如果拋出的异常没有被 catch 块捕获,例如,将catch(int e),改为catch(char e),当输入的 n 为 0 时,拋出的整型异常就没有 catch 块能捕获,这个异常也就得不到处理,那么程序就会立即中止,try…catch 后面的内容都不会被执行
(9)如果希望不论拋出哪种类型的异常都能捕获,可以编写如下 catch 块:

catch(...) {
    ...
}

(10)示例:

#include <iostream>
using namespace std;
int main(){
	double m ,n;
	cin >> m >> n;
	try {
		cout << "before dividing." << endl;
		if( n == 0)
			throw -1; //抛出整型异常
		else if( m == 0 )
			throw -1.0; //抛出double型异常
		else
			cout << m / n << endl;
			cout << "after dividing." << endl;
	}
	catch(double d) {
		cout << "catch(double) " << d << endl;
	}
	catch(...) {
		cout << "catch(...) " << endl;
	}
	cout << "finished" << endl;
	return 0;
}
程序运行结果:
9 0↙
before dividing.
catch(...)
finished
0 6↙
before dividing.
catch(double) -1
finished

(11)如果有多个符合的catch块,执行前面的,也就是catch块从上往下执行

3)异常的再抛出:如果一个函数在执行的过程中,抛出的异常在本函数内就被catch块捕获并处理了,那么该异常就不会抛给这个函数的调用者(也称“上一层的函数”);如果异常在本函数中没被处理,就会被抛给上一层的函数。
(1)示例:

#include <iostream>
#include <string>
using namespace std;
class CException{
public:
    string msg;
    CException(string s) : msg(s) {}
};
double Devide(double x, double y){
    if (y == 0)
        throw CException("devided by zero");
    cout << "in Devide" << endl;
    return x / y;
}
int CountTax(int salary){
    try {
        if (salary < 0)
            throw - 1;
        cout << "counting tax" << endl;
    }
    catch (int) {
        cout << "salary < 0" << endl;
    }
    cout << "tax counted" << endl;
    return salary * 0.15;
}
int main()
{
    double f = 1.2;
    try {
        CountTax(-1);
        f = Devide(3, 0);
        cout << "end of try block" << endl;
    }
    catch (CException e) {
        cout << e.msg << endl;
    }
    cout << "f = " << f << endl;
    cout << "finished" << endl;
    return 0;
}
输出结果:
salary < 0
tax counted
devided by zero
f=1.2
finished

4)C++标准异常类: C++标准库中有一些类代表异常,这些类都是从exception类派生而来
在这里插入图片描述
(1)bad_cast:在用 dynamic_cast进行从多态基类对象(或引用),到派生类的引用的强制类型转换时,如果转换是不安全的,则会抛出此异常

#include <iostream>
#include <stdexcept>
using namespace std;
class Base{
    virtual void func() {}
};
class Derived : public Base{
public:
    void Print() {}
};
void PrintObj(Base & b){
    try {
        Derived & rd = dynamic_cast <Derived &>(b);
        //此转换若不安全,会拋出 bad_cast 异常
        rd.Print();
    }
    catch (bad_cast & e) {
        cerr << e.what() << endl;
    }
}
int main(){
    Base b;
    PrintObj(b);
    return 0;
}
输出结果:
Bad dynamic_cast!

(2)bad_alloc:在用new运算符进行动态内存分配时,如果没有足够的内存,则会引发此异常。

#include <iostream>
#include <stdexcept>
using namespace std;
int main (){
	try {
		char * p = new char[0x7fffffff];
		//无法分配这么多空间,会抛出异常
	}
	catch (bad_alloc & e) {
		cerr << e.what() << endl;
	}
	return 0;
}
输出结果:
bad allocation

(3)out_of_range:用vector或string的at成员函数根据下标访问元素时,如果下标越界,就会抛出此异常。例如:

#include <iostream>
#include <stdexcept>
#include <vector>
#include <string>
using namespace std;
int main (){
	vector<int> v(10);
	try {
		v.at(100)=100; //抛出out_of_range异常
	}
	catch (out_of_range& e) {
		cerr << e.what() << endl;
	}
	string s = "hello";
	try {
		char c = s.at(100); //抛出out_of_range异常
	}
	catch (out_of_range& e) {
		cerr << e.what() << endl;
	}
	return 0;
}
输出结果:
invalid vector<T> subscript
invalid string position
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值