本文开始将会介绍智能指针的相关内容,最后达到你知道什么事智能指针,智能指针怎么使用?存在什么问题?如何去解决这些问题?最后可以模仿标准库中的智能指针,写一套自己的智能指针。
本文主要介绍什么是智能指针?什么是RAII?
C++中最令人头疼的问题是强迫程序员对申请的资源(文件,内存等)进行管理,一不小心就会出现泄露(忘记对申请的资源进行释放)的问题。
C++新特性14_智能指针与RAII
1. C++中内存分配过程及问题
C++设计过程中,我们会采用new的方式进行资源分配。利用new在堆上分配内存对应大小的内存,定义及运行结果如下:
int* p = new int;
此处涉及调试堆,fd作为开始结束的标志,"cd cd cd cd"代表开辟的内存,四个字节。

p指向的地址分配了内容之后:

然而一旦分配就需要手动管理堆得释放,否则当出了作用域,申请的堆内存存依然是存在的。
C++中最令人头疼的问题是强迫程序员对申请的资源(文件,内存等)进行管理,一不小心就会出现泄露(忘记对申请的资源进行释放)的问题。
java/python中使用了垃圾回收技术,不再需要人为管理,内部的虚拟机会自动释放不需要使用的资源。
//使用了垃圾回收技术,不在需要人为管理,相关的虚拟机会自动释放不需要使用的资源。
// Java
ArrayList<int> list = new ArrayList<int>();
2. C++的解决办法:RAII(语法层次的解决)
在传统 C++ 里我们只好使用 new 和 delete 去『记得』对资源(内存、文件、临界区、互斥体等)进行释放。而 C++11 引入了智能指针的概念,使用了引用计数的想法,让程序员不再需要关心手动释放内存。
2.1 解决思路:RAII资源管理方式
利用C++中一个对象出了其作用域会被自动析构,因此我们只需要在构造函数的时候申请空间,而在析构函数(在离开作用域时调用)的时候释放空间,这样,就减轻了程序员在编码过程中,考虑资源释放的问题,这就是RAII。
RAII,完整的英文是 Resource Acquisition Is Initialization 是 C++ 所特有的资源管理方式。
- 有少量其他语言,如 D、Ada 和 Rust 也采纳了 RAII,但主流的编程语言中, C++ 是唯一一个依赖 RAII 来做资源管理的。
- RAII 依托栈和析构函数,来对所有的资源——包括堆内存在内——进行管理。对 RAII 的使用,使得 C++ 不需要类似于 Java 那样的垃圾收集方法,也能有效地对内存进行管理。
具体而言,C11的stl中为大家带来了3种智能指针,正确合理的使用可以有效的帮助大家管理资源,当然,在C++的使用智能指针没有像Java,python这种具备垃圾回收机制的语言那么舒适,毕竟,程序员还需要做一些额外的事情,但是,这远比传统的C或者C++更加优雅。
2.2 解决方法本质举例
智能指针的过程都可以简单的看作以下利用对象的构造析构的程序过程:
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
class CTest
{
public:
CTest() {
cout << "CTest()" << endl;
//在构造中完成资源的初始化
m_pInt= new int;
}
~CTest() {
cout << "CTest()" << endl;
if (m_pInt!=nullptr) {
//在析构中完成资源的释放
delete m_pInt;
}
}
private:
int* m_pInt;
};
//全局对象,即使在main函数中没有调用,依然会调用进行构造及析构
CTest test;
int main()
{
return 0;
}
2.3 RAII资源管理方式中的3种智能指针
- std::shared_ptr 强指针
- std::unique_ptr
- std::weak_ptr 弱指针
一般shared_ptr 强指针和weak_ptr弱指针是一起使用的
在早期有一个auto_ptr,这四种指针在使用上有区别:
- auto_ptr有缺陷是过时的产物。
- unique_ptr对auto_ptr的问题进行了修正。
- shared_ptr使用了引用计数,但是会出现循环引用的问题需要配合后面的weak_ptr一起使用。
3.学习视频地址:智能指针与RAII
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
void* alloc_data()
{
int* p = new int;
return 0;
}
//打开文件
FILE* open_file(char* name)
{
FILE* fp = nullptr;
fp=fopen(name,"rb+");
return fp;
}
class CTest
{
public:
CTest() {
cout << "CTest()" << endl;
//在构造中完成资源的初始化
m_pInt= new int;
}
~CTest() {
cout << "CTest()" << endl;
if (m_pInt!=nullptr) {
//在析构中完成资源的释放
delete m_pInt;
}
}
private:
int* m_pInt;
};
//全局对象,即使在main函数中没有调用,依然会调用进行构造及析构
CTest test;
int main()
{
//new定义之后会在堆上分配内存
//c++需要自己去管理堆内存的申请和释放
//int* p = new int;
//alloc_data();
//按道理在函数外部堆资源进行释放
//忘记资源的释放,会导致资源泄漏(长时间分配但不释放,内存会越来越小)
return 0;
}
4. 学习笔记:智能指针与RAII
本文介绍了C++中智能指针的基本概念及其如何通过RAII(Resource Acquisition Is Initialization)机制解决资源管理问题,特别是内存管理问题。通过智能指针,程序员可以在C++中更优雅地管理资源,避免内存泄漏等问题。

1332

被折叠的 条评论
为什么被折叠?



