int div()
{
int a, b;
cin >> a >> b;
if (b == 0)
throw invalid_argument("除0错误");
return a / b;
}
void Func()
{
int* p1 = new int;
int* p2 = new int;
cout << div() << endl;
delete p1;
delete p2;
}
int main()
{
try
{
Func();
}
catch (exception& e)
{
cout << e.what() << endl;
}
return 0;
}
很明显 若p2抛异常那么需要释放p1 若div函数抛异常 那么需要释放p1 p2 …怎么改进代码?
int div()
{
int a, b;
cin >> a >> b;
if (b == 0)
throw invalid_argument("除0错误");
return a / b;
}
void Func()
{
int* p1 = new int;
int* p2 = nullptr;
try
{
p2 = new int;
}
catch (...)
{
delete p1;
throw;
}
try
{
cout << div() << endl;
}
catch (...)
{
delete p1;
delete p2;
throw;
}
delete p1;
delete p2;
}
int main()
{
try
{
Func();
}
catch (exception& e)
{
cout << e.what() << endl;
}
return 0;
}
如果后续还有更多 那么就需要我们一个一个搞 怎么办???
内存泄漏:因为疏忽或错误造成程序未能释放已不再使用的内存的情况 内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
void MemoryLeaks()
{
// 1.内存申请了忘记释放
int* p1 = (int*)malloc(sizeof(int));
int* p2 = new int;
// 2.异常安全问题
int* p3 = new int[10];
Func(); // Func函数抛异常导致 delete[] p3未执行 p3没被释放.
delete[] p3;
}
危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等,出现内存泄漏会导致响应越来越慢,最终卡死。
linux下内存泄漏检测:linux下几款内存泄漏检测工具
windows下第三方工具:VLD工具说明
其他工具:内存泄漏工具比较
1、事前预防型。如智能指针。2、事后查错型。如泄漏检测工具。
智能指针(现代 C++)
RAII (Resource Acquisition Is Initialization)
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;
}
private:
T* _ptr;
};
int div()
{
int a, b;
cin >> a >> b;
if (b == 0)
throw invalid_argument("除0错误");
return a / b;
}
void Func()
{
SmartPtr<int> sp1(new int(1));
SmartPtr<int> sp2(new int(2));
cout << div() << endl;
*sp1 = 10;
cout << *sp1 << endl;
cout << *sp2 << endl;
}
int main()
{
try
{
Func();
}
catch (exception& e)
{
cout << e.what() << endl;
}
return 0;
}
p1抛异常没问题 p2抛异常当前函数栈帧结束 p1对象析构 div函数抛异常 同前
RAII(Resource Acquisition Is Initialization) : 一种利用对象生命周期来控制程序资源(如内
存、文件句柄、网络连接、互斥量等等)的简单技术。
> 对象构造时获取资源,控制对资源的访问使之在对象的生命周期内始终保持有效,
> 对象析构时释放资源。实际上把管理资源的责任托管给了一个对象
> 一个类对象销毁时自动调用构造函数和析构函数 当函数栈帧销毁时对象自动销毁
> 实际上是因为这两个固有的"自动"成就了智能指针
不需要显式释放资源
对象所需资源在其生命期内始终保持有效
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;
}
private:
T* _ptr;
};
int div()
{
int a, b;
cin >> a >> b;
if (b == 0)
throw invalid_argument("除0错误");
return a / b;
}
void Func()
{
SmartPtr<int> sp1(new int(1));
SmartPtr<int> sp2(new int(2));
cout << div() << endl;
*sp1 = 10;
cout << "* sp1 == " << *sp1 << endl;
cout << "* sp2 == " << *sp2 << endl;
}
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;
}
private:
T* _ptr;
};
int main()
{
SmartPtr<int> sp1(new int(1));
SmartPtr<int> sp2(sp1);
return 0;
}
很明显这里时之前就讲过的深拷贝问题 函数结束时对同一块空间释放两次 有人说直接深拷贝不就ok了?
而这样的回答实际上时忘记了我们设计智能指针的初衷 即它要像指针一样工作 对于指针的拷贝就是两个不同的指针指向同一块空间 那怎么办?
有的人可能有这样的问题 之前的模拟实现容器时 我们自己搞了一个迭代器 为什么迭代器的浅拷贝没问题 而智能指针的而浅拷贝有问题?
迭代器是一个类 对于一个类对象 当对象销毁 会调用析构函数 默认生成的析构函数对于内置类型不做处理 对于自定义类型调用他的析构函数 自己实现的迭代器没有手写析构函数 于是调用自动生成的 而在迭代器里 指针是一个内置类型 不做处理
而在智能指针类里 我们手写了析构函数 并且在这个析构函数里还释放了指针指向的空间于是就造成了上述问题
C++98#include
template<class T>
class auto_ptr
{
public:
auto_ptr(T* ptr)
:_ptr(ptr)
{
}
~auto_ptr()
{
if (_ptr)
{
cout << "delete:" << _ptr << endl;
delete _ptr;
}
}
//构造函数: 管理权转移
auto_ptr(auto_ptr<T>& ap)
:_ptr(ap._ptr)
{
ap._ptr = nullptr;
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
private:
T* _ptr;
};
void test_auto()
{
auto_ptr<int> ap1(new int(1));
auto_ptr<int> ap2(ap1);
//ap1失去管理权 悬空指针
*ap1 = 1;
*ap2 = 1;
}
C++98
C++11
C++11中类与对象推出的新功能 [补充讲解final/override关键字]
template<class T>
class unique_ptr
{
public:
unique_ptr(T* ptr)
:_ptr(ptr)
{
}
~unique_ptr()
{
if (_ptr)
{
cout << "delete:" << _ptr << endl;
delete _ptr;
}
}
T& operator*()
{
return *_ptr;
}
T* operator->()
{
return _ptr;
}
// C++11防拷贝
unique_ptr(const unique_ptr<T>& up) = delete;
unique_ptr<T>& operator=(const unique_ptr<T>& up) = delete;
/*
private:
// C++98防拷贝
// 1.声明为私有 --禁止在类外实现
// 2.不实现 --编译器不自动生成浅拷贝
unique_ptr(const unique_ptr& up);
unique_ptr& operator=(const unique_ptr& up);
*/
private:
T* _ptr;
};
void test_unique()
{
unique_ptr<int> up1(new int(1));
//unique_ptr up2(up1);
}