目录
异常
一、异常
编程过程中的常见错误类型
语法错误
逻辑错误
异常
……
异常是一种在程序运行过程中的发生的不好预测的错误(比如内存不够)
异常没有被处理,会导致程序终止
为了增强可读性和方便团队协作,如果函数内部可能会抛出异常,建议函数声明一下异常类型
//int divide(int v1,int v2) throw(){//不抛出任何异常
//int divide(int v1,int v2) throw(const char*,int){//只抛出const char*,int类型的异常
int divide(int v1,int v2){//抛出任意可能的异常
if (v2 == 0) {
throw "不能除以0";
// throw 0;
}
return v1/v2;
/**
throw异常后,会在当前函数中查找匹配的catch,找不到就
终止当前函数代码,去上一层函数中查找。如果最终都找不
到匹配的catch,整个程序就会终止
但一般不会在抛出异常的函数里再捕获异常
*/
// try {
// if (v2 == 0) { throw "不能除以0";}
// return v1/v2;
// } catch (const char* exception) {
// cout<<"exception0 = "<<exception<<endl;
// }
// return 0;
}
void divideTest(){
try {
//被检测的代码
int a = 10;
int b = 0;
int c = divide(a, b);
cout<<"c = "<<c<<endl;
} catch (const char* exception) {
//异常处理代码
cout<<"exception = "<<exception<<endl;
} catch(int exceptionCode){
//异常处理代码
cout<<"exceptionCode = "<<exceptionCode<<endl;
}
}
void memoryTest() {
cout << "1" << endl;
// 如果内存不够,就会抛出异常(运行过程中抛出一个错误)
try {
for (int i = 0; i < 9999999; i++) {
int *p = new int[9999999];
}
cout << "2" << endl;
}
catch (...) {
//拦截所有异常类型
cout << "发生了异常" << endl;
}
cout << "3" << endl;
// delete[] p;
}
二、自定义异常类型
class Exception{
public:
virtual string what() const= 0;
};
class DivideException:public Exception{
public:
string what() const{
return "不能除以0";
};
};
int divideFun(int v1,int v2) throw(Exception){
if (v2 == 0) {
throw DivideException();
}
return v1/v2;
}
void customExceptionTest(){
try {
int a = 10;
int b = 0;
int c = divideFun(a, b);
} catch (const Exception & exception) {
cout<<"exception.what()"<<exception.what()<<endl;
}
cout<<"running..."<<endl;
}
三、标准异常类型
void biaoZhunExceptionTest(){
try {
int size = 9999999;
for (int i=0; i<size; i++) {
int* p = new int[size];
}
} catch (const std::bad_alloc& exception) {
cout<<"exception.what() = "<<exception.what()<<endl;
}
cout<<"running..."<<endl;
}
智能指针
一、定义两个类
class Car;
class Person{
public:
shared_ptr<Car> m_car = nullptr;
Person(){
cout<<"Person::Person()"<<endl;
}
~Person(){
cout<<"Person::~Person()"<<endl;
}
void run(){
cout<<"Person::run()"<<endl;
}
};
class Car{
public:
// shared_ptr<Person> m_person = nullptr;
weak_ptr<Person> m_person;
Car(){
cout<<"Car::Car()"<<endl;
}
~Car(){
cout<<"Car::~Car()"<<endl;
}
};
二、智能指针使用
传统指针存在的问题
需要手动管理内存
容易发生内存泄露(忘记释放、出现异常等)
释放之后产生野指针(野指针:指向了已经释放了的内存;)
智能指针就是为了解决传统指针存在的问题
auto_ptr:属于C++98标准,在C++11中已经不推荐使用(有缺陷,比如不能用于数组)
shared_ptr:属于C++11标准
unique_ptr:属于C++11标准
void smartPointTest(){
cout<<"1"<<endl;
{
Person * p = new Person();//不会自动释放
shared_ptr<Person> p1(new Person());//智能指针会自动释放
shared_ptr<Person> p2 = shared_ptr<Person>(new Person());//智能指针会自动释放
p1->run();
p2->run();
}
cout<<"2"<<endl;
}
三、智能指针的简单自实现
template<class T>
class SmartPointer{
T* m_pointer;
public:
SmartPointer(T* pointer):m_pointer(pointer){}
~SmartPointer(){
if (m_pointer == nullptr) return;
delete m_pointer;
}
T* operator->(){
return m_pointer;
}
};
void smartPointerTest2(){
cout<<"1"<<endl;
{
SmartPointer<Person> p1(new Person());
p1->run();
//p1.operator->()->run();
SmartPointer<Person> p2 = SmartPointer<Person>(new Person());
p2->run();
}
cout<<"2"<<endl;
}
四、智能指针设计原理
多个shared_ptr可以指向同一个对象,当最后一个shared_ptr在作用域范围内结束时,对象才会被自动释放
一个shared_ptr会对一个对象产生强引用(strong reference)
每个对象都有个与之对应的强引用计数,记录着当前对象被多少个shared_ptr强引用着
可以通过shared_ptr的use_count函数获得强引用计数
当有一个新的shared_ptr指向对象时,对象的强引用计数就会+1
当有一个shared_ptr销毁时(比如作用域结束),对象的强引用计数就会-1
当一个对象的强引用计数为0时(没有任何shared_ptr指向对象时),对象就会自动销毁(析构)
void sharedPtrTheory(){
shared_ptr<Person> ptr1(new Person());
cout<<ptr1.use_count()<<endl;//1
{
shared_ptr<Person> ptr2 = ptr1;
cout<<ptr1.use_count()<<endl;///2
}
cout<<ptr1.use_count()<<endl;//1
}
void sharedPtrNote(){
//shared_ptr的注意点
/**
不要使用裸指针来初始化智能指针,比如以下代码
*/
Person * p = new Person();
cout<<"p = "<<p<<endl;
{
shared_ptr<Person> ptr1(p);
cout<<"ptr1 = "<<ptr1<<endl;
cout<<ptr1.use_count()<<endl;
}
//离开作用域person对象释放,此时p指针应该是野指针
{
shared_ptr<Person> ptr2(p);
cout<<"ptr2 = "<<ptr2<<endl;
cout<<ptr2.use_count()<<endl;
}
//离开作用域重复释放person对象,
//报错 malloc: *** error for object 0x102834560: pointer being freed was not allocated
cout<<"-----------------"<<endl;
// 可以通过一个已存在的智能指针初始化一个新的智能指针
shared_ptr<Person> ptr3(new Person());
shared_ptr<Person> ptr4(ptr3);
shared_ptr<Person> ptr5 = ptr3;
cout<<ptr3.use_count()<<endl;
}
unique_ptr
unique_ptr也会对一个对象产生强引用,它可以确保同一时间只有1个指针指向对象
当unique_ptr销毁时(作用域结束时),其指向的对象也就自动销毁了
可以使用std::move函数转移unique_ptr的所有权
void uniquePtrTest(){
//ptr强引用这Person对象
unique_ptr<Person> ptr(new Person());
cout<<"1"<<endl;
cout<<"ptr = "<<ptr<<endl;//ptr = 0x100695880
{
//转移之后ptr2强引用这Person对象
unique_ptr<Person> ptr2 = std::move(ptr);
cout<<"ptr2 = "<<ptr2<<endl;//ptr = 0x100695880
cout<<"ptr = "<<ptr<<endl;//ptr = 0x0
cout<<"2"<<endl;
}
cout<<"3"<<endl;
}
智能指针与数组
针对数组的用法
shared_ptr的数组智能指针,有和->操作,但不支持下标操作[],只能通过get()去访问数组的元素。
shared_ptr的数组智能指针,必须要自定义deleter
unique_ptr的数组智能指针,没有和->操作,但支持下标操作[]
参考文章:https://www.cnblogs.com/xiaoshiwang/p/9726511.html
void sharedPtrForArray(){
shared_ptr<Person> ptr1(new Person[5]{},[](Person*p){delete [] p;});
ptr1.get()->run();//数组的第一个元素
(ptr1.get()+1)->run();//数组的第二个元素
// shared_ptr<Person[]> ptr2(new Person[5]{});//不支持
unique_ptr<Person[]> persons(new Person[5]{});
persons[0].run();
}
shared_ptr的循环引用
void cycleReferenceTest(){
shared_ptr<Person> ptr_person(new Person());
shared_ptr<Car> ptr_car(new Car());
ptr_person->m_car = ptr_car;
ptr_car->m_person = ptr_person;
/**
离开当前函数的作用域后person对象和car对象都不会销毁,产生了强引用
见图:cycleReference.png。离开作用域只是画X号的两个强引用消失了,剩下的实线形成循环引用
如果将Car内的成员变量m_person或Person内的成员变量m_car变为弱引用即可解决循环引用的问题
见图:weakPtr.png
//shared_ptr<Person> m_person = nullptr;
weak_ptr<Person> m_person;
*/
}
行者常至,为者常成!