RAII
它是一套编译器对象回收机制,要求代码必须以
class
的形式组织,这套机制会利用class
的constructor
和destructor
来释放对象/资源/内存
.
备注:这套机制跟try ... catch
没有任何关系, 他们是完全不同的两套机制.
代码准备:
#include <iostream>
using std::cout;
using std::endl;
class Person {
private:
int * age;
public:
Person(int * a = new int(10)): age(a) {
cout << "initialize Person class." << endl;
};
~Person() {
cout << "destroy Person class." << endl;
delete age;
}
friend std::ostream & operator<<(std::ostream & os, Person & ps) {
os << *ps.age;
return os;
};
};
- 函数正常退出,编译器会正常回收所有常规对象
int a = 10;
vector<int> b {1, 2, 3, 4, 5};
string b = "hello";
void func() { Person ps{}; } int main(void) { func(); // 触发 ~Person , 并且是再`end.`前面触发的. cout << "end." << endl; return 0; } // output: // initialize Person class. // destroy Person class. // end.
- 函数正常退出,编译器不会回收
new
的对象
int * a = new int(10);
void func() { Person * ps = new Person{}; } int main(void) { func(); // 函数退出,没有触发 ~Person . return 0; } // 程序退出, 没有触发 ~Person . // output: // initialize Person class.
- 函数异常退出,编译器会正常回收所有常规对象
这里可能比较难理解,加一下备注:try { }
这里是一个作用域,func();
报错后,会退出这个作用域,进入到catch
作用域, 所以它会先触发析构函数
然后再打印catch
作用域里面的代码.void func() { Person ps{}; throw std::exception(); } int main(void) { try { func(); return 0; } catch (std::exception & e) { cout << "catching error." << endl; return 1; } } // output: // initialize Person class. // destroy Person class. // catching error.
- 函数异常退出,编译器不会回收
new
对象void func() { Person * ps = new Person{}; throw std::exception(); } int main(void) { try { func(); return 0; } catch (std::exception & e) { cout << "catching error." << endl; return 1; } } // output: // initialize Person class. // catching error.
智能指针
你不可能每写一行代码都要封装一个类对象然后再去写把? 搞死你咯.
智能指针就是让你想要在使用new
的地方包裹一层shared_ptr
或weak_ptr
或unique_ptr
,它是一个class
,所以它能利用RAII
机制, 这样你就不需要再每写一个代码都要去写一个类对象, 起到一个简化(helper)作用.
问题
透过上面最后两个异常例子,可以得知,如果不做try
处理,整个程序都直接abort
了,就别提内存回收了; 如果做了try
至少还尝试去回收一些常规的对象, 但是new
出来的对象绝对不会帮你回收.-
答案
通过这样写代码, 至少你不是无限的写class
.void func() { std::shared_ptr<Person> ps(new Person{}); throw std::exception(); } int main(void) { try { func(); return 0; } catch (std::exception & e) { cout << "catching error." << endl; return 1; } } // output: // initialize Person class. // destroy Person class. // catching error.