【C++航海王:追寻罗杰的编程之路】智能指针
目录
1 -> 为什么需要智能指针?
2 -> 内存泄漏
2.1 ->什么是内存泄漏,以及内存泄漏的危害
2.2 -> 内存泄漏分类
2.3 -> 如何避免内存泄漏
3 -> 智能指针的使用及原理
3.1 -> RAII
3.2 -> 智能指针的原理
3.3 -> std::auto_ptr
3.4 -> std::unique_ptr
4 -> C++11和boost中智能指针的关系
1 -> 为什么需要智能指针?
先分析下面这段程序有没有什么内存方面的问题?
#define _CRT_SECURE_NO_WARNINGS 1 #include using namespace std; int div() { int a, b; cin >> a >> b; if (b == 0) throw invalid_argument("除0错误"); return a / b; } void Func() { // 1、如果p1这里new 抛异常会如何? // 2、如果p2这里new 抛异常会如何? // 3、如果div调用这里又会抛异常会如何? int* p1 = new int; int* p2 = new int; cout 如何避免内存泄漏
- 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记得释放。ps:这个是理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智能指针来管理才有保证。
- 采用RAII思想或者智能指针来管理资源。
- 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
- 出问题了使用内存泄漏工具检测。ps:不过很多工具都不靠谱,或者收费昂贵。
总结:
内存泄漏非常常见,解决方案分为两种:
- 事前预防型。如智能指针等;
- 事后查错型。如泄漏检测工具。
3 -> 智能指针的使用及原理
3.1 -> RAII
RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:
- 不需要显式地释放资源。
- 采用这种方式,对象所需的资源在其生命周期内始终保持有效。
// 使用RAII思想设计的SmartPtr类 template class SmartPtr { public: SmartPtr(T* ptr = nullptr) : _ptr(ptr) {} ~SmartPtr() { if (_ptr) delete _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 sp1(new int); SmartPtr sp2(new int); cout () { return _ptr; } private: T* _ptr; }; struct Date { int _year; int _month; int _day; }; int main() { SmartPtr sp1(new int); *sp1 = 10; cout _year = 2018; // 本来应该是sparray->->_year这里语法上为了可读性,省略了一个-> sparray->_year = 2018; sparray->_month = 1; sparray->_day = 1; }
总结一下智能指针的原理:
- RAII特性
- 重载operator*和operator->,具有像指针一样的行为。
3.3 -> std::auto_ptr
std::auto_ptr文档介绍
C++98版本的库中就提供了auto_ptr的智能指针。下面演示auto_ptr的使用及问题。
auto_ptr的实现原理:管理权转移的思想,下面简化模拟实现了一份fyd::auto_ptr来了解它的原理。
// C++98 管理权转移 auto_ptr namespace fyd { template class auto_ptr { public: auto_ptr(T* ptr) :_ptr(ptr) {} auto_ptr(auto_ptr& sp) :_ptr(sp._ptr) { // 管理权转移 sp._ptr = nullptr; } auto_ptr& operator=(auto_ptr& ap) { // 检测是否为自己给自己赋值 if (this != &ap) { // 释放当前对象中资源 if (_ptr) delete _ptr; // 转移ap中资源到当前对象中 _ptr = ap._ptr; ap._ptr = NULL; } return *this; } ~auto_ptr() { if (_ptr) { cout () { return _ptr; } T* get() const { return _ptr; } private: T* _ptr; int* _pRefCount; mutex* _pmtx; }; // 简化版本的weak_ptr实现 template class weak_ptr { public: weak_ptr() :_ptr(nullptr) {} weak_ptr(const shared_ptr& sp) :_ptr(sp.get()) {} weak_ptr& operator=(const shared_ptr& sp) { _ptr = sp.get(); return *this; } T& operator*() { return *_ptr; } T* operator->() { return _ptr; } private: T* _ptr; }; } struct Date { int _year = 0; int _month = 0; int _day = 0; }; void SharePtrFunc(fyd::shared_ptr& sp, size_t n, mutex& mtx) { cout _month++; copy->_day++; } } } int main() { fyd::shared_ptr p(new Date); cout
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。