一、异常的关键记忆点

  1. 异常是一种处理错误的方式,它允许程序在遇到无法正常执行的状况时,跳出当前的执行流程,并寻找一个异常处理程序来处理这个错误。也就是将错误代码和正常代码分离开来。
  2. 当程序出现问题时,会通过抛出(throw)一个对象来引发一个异常,后续会用catch捕捉这个异常。
  3. 这个对象的类型和调用链决定了由哪个catch代码来处理这个异常,会选择类型匹配且离抛出位置最近的catch来处理。
  4. 异常抛出时,后面的代码将不会再执行,会直接跳转到catch位置处理异常。 而这可能会存在内存泄漏问题,比如new出一块内存,在之后是要用delete释放的,而一旦new的时候发生了异常跳过了delete到catch,资源就没有得到释放。
  5. 处理异常导致的内存泄漏问题有两个解决办法,一个是不断嵌套try…catch语句,因为抛出异常的语句不同对应需要释放的资源也可能不同,还有一个就是接下来要讲到的智能指针
  6. 这个抛出的对象是一个异常对象的拷贝,因为这个异常对象极有可能是一个局部对象,这个拷贝的对象在catch语句执行完销毁。
  7. 这里也存在类型转换:非常量(const)到常量(权限缩小),数组转换为指向数组元素类型的指针,函数转换为指向函数的指针,以及派生类类型到基类类型的转换。
  8. 一般main语句中会**catch(…)**来捕捉异常,这样可以避免程序终止(如果一个异常直到main函数都没有匹配的catch语句,编译器会调用terminate函数终止程序。
  9. 异常捕获之后可以用throw再次直接抛出。
  10. C++11里:加上noexcept的函数代表不会抛异常。

二、智能指针

1. RAII与智能指针
  1. RAII是Resource Acquisition Is Initialization的缩写,它是一种管理资源的类的设计思想,它利用对象生命周期来管理获取到的动态资源,因为对象出作用域后会自动调用析构函数,自动释放资源,从而避免资源泄漏。这里的资源可以是内存、文件指针、网络连接、互斥锁等。
  2. RAII在获取资源后会把资源交给这个类的对象进行管理,通过这个对象控制对资源的访问,资源会在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源
  3. 智能指针类就是一个满足了RAII设计思路的类,同时重载了operator->/operator*/operatro[]等运算符,实现对资源的访问。
  4. 我的理解是:智能指针类通过传递给它的一个指针来构造一个对象,本质是对这个指针的封装,将这个指针升级为了能够自动调用析构的对象,从而避免内存泄漏。

一个智能指针类的基本结构:

代码语言:javascript

AI代码解释

template<class T>
class SmartPtr
{
public:
	SmartPtr(T* ptr)
		:_ptr(ptr)
	{
	}

	~SmartPtr()
	{
		cout << "delete:" << _ptr << endl;
		delete[] _ptr;
	}

	// 重载运算符,模拟指针的行为,方便访问资源
	T& operator*()
	{
		return *_ptr;
	}

	T* operator->()
	{
		return _ptr;
	}

	T& operator[](size_t i)
	{
		return _ptr[i];
	}

public:
	T* _ptr;
};
2. C++标准库智能指针的使用

C++标准库中的智能指针都在头文件<memory>里,只要包了这个头文件就能够使用接下来的几种智能指针。 其中出了weak_ptr智能指针外,其他的都是应用了RAII的设计思路。

2.1 auto_ptr
  1. auto_ptr是C++98版本里设计出来的智能指针,它会在拷贝时将这个智能指针对象管理的资源转移给拷贝出的智能指针对象。这就会导致一个问题,那就是原来的智能指针对象会置空。这个时候如果我们调用原来的智能指针对象访问资源就会访问报错,因为它不再管理任何资源了。不建议使用这个智能指针。

代码语言:javascript

AI代码解释

struct Date
{
	int _year;
	int _month;
	int _day;
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{}

	~Date()
	{
		cout << "~Date()" << endl;
	}
};
int main()
{
	auto_ptr<Date> ap1(new Date);

	auto_ptr<Date> ap2(ap1);
	return 0;
}

拷贝之前:

在这里插入图片描述

在这里插入图片描述

拷贝之后,可以看到,ap1被置空了,它的管理的资源都转移到了ap2那里。

在这里插入图片描述

在这里插入图片描述

2.2 unique_ptr

在这里插入图片描述

在这里插入图片描述

  1. unique_ptr是C++11版本里设计出来的智能指针,被译为唯一指针它只支持移动,不支持拷贝。如果是将右值的资源交给智能指针管理,就非常推荐使用它。

代码语言:javascript

AI代码解释

unique_ptr<Date> up1(new Date);//用指向资源的指针进行构造
unique_ptr<Date> up2(up1);//不支持拷贝
unique_ptr<Date> up3 = make_unique<Date>();//支持make_unique,移动构造
unique_ptr<Date> up4(Date());//易错点,这里编译器会识别成函数声明,这样调用不了移动构造
up1 = up2;//不支持赋值
  1. 要注意的是up4会被编译器识别为函数声明,而不会调用移动构造。如果要使用移动构造管理临时对象的资源,最好使用make_unique(c++14引入)函数模板,可以直接进行构造。
2.3 shared_ptr
  1. shared_ptr是C++11版本里设计出来的智能指针,被译为共享指针,它既支持移动,也支持拷贝。
  2. 它拷贝出来的智能指针对象会与它一起管理这个资源。它的底层是用引用计数来实现的。具体会在接下来的原理部分讲解。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐