文章目录
🎖 博主的CSDN主页:Ryan.Alaskan Malamute
📜 博主的代码仓库主页 [ Gitee ]:@ryanala [GitHub]: Ryan-Ala
智能指针的介绍
在C++中,动态内存的使用很容易出问题,因为要确保在正确的时间释放内存是极其困难的。有时会忘记释放内存,在这种情况下会产生内存泄露;有时在尚有指针引用内存的情况下就释放了它,在这种情况下就会产生引用非法内存的指针。
C++智能指针是包含重载运算符的类,其行为像常规指针,但智能指针能够及时、妥善地销毁动态分配的数据,并实现了明确的对象生命周期,因此更有价值。
RAII
RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个象。
这种做法有两大好处:
- 不需要显式地释放资源。
- 采用这种方式,对象所需的资源在其生命期内始终保持有效
unique_ptr
unique_ptr 是从 C++ 11 开始,定义在 中的智能指针(smart pointer)。它持有对对象的独有权,即两个 unique_ptr 不能指向一个对象,不能进行复制操作只能进行移动操作。
unique_ptr 之所以叫这个名字,是因为它智能指向一个对象,即当它指向其他对象时,之前所指向的对象会被摧毁。其次,当 unique_ptr 超出作用域时,指向的对象也会被自动摧毁。
使用unique_ptr需要包含头文件:
#include<memory>
unique_ptr 的定义
//non-specialized
template <class T, class D = default_delete<T>> class unique_ptr;
//array specialization
template <class T, class D> class unique_ptr<T[],D>;
unique_ptr 是 C++ 11 提供的用于防止内存泄漏的智能指针中的一种实现,独享被管理对象指针所有权的智能指针。
unique_ptr对象包装一个原始指针,并负责其生命周期。当该对象被销毁时,会在其析构函数中删除关联的原始指针。
unique_ptr的使用
1. 创建和初始化
#include <iostream>
#include <memory>
using namespace std;
int mian()
{
unique_ptr<int> p; // 可以指向int对象的一个空智能指针
unique_ptr<int> p(new int(105)); // p指向一个值为105的int对象
auto p(new int(105)); // 不能简写为auto,这里auto推断出是普通指针
}
2. make_unique
C++14 才有的 make_unique,还需要注意的是,make_unique 不支持定制删除器
#include <iostream>
#include <memory>
using namespace std;
int mian()
{
unique_ptr<int> p = make_unique<int>(100);
auto p = make_unique<int>(200);
}
3. unique_ptr不支持 拷贝构造 和 拷贝赋值
一个 unique_ptr 唯一拥有它指向的对象,因此 unique_ptr 不支持普通的拷贝构造和拷贝赋值操作。
4. unique_ptr支持 移动构造 和 移动赋值
#include <iostream>
#include <memory>
using namespace std;
int mian()
{
unique_ptr<string> p1(new string("hello"));
unique_ptr<string> p2(std::move(p1));
// 移动构造一个新的智能指针对象p2,p1变成空,p2指向该内存
return 0;
}
5. 转换成shared_ptr
如果 unique_ptr 为右值,就可以将它赋值给 shared_ptr。因为 shared_ptr 包含一个显式构造函数,可用于将右值 unqiue_ptr 转换为 shared_ptr,shared_ptr 将接管原来归 unique_ptr 所拥有的对象。
#include <iostream>
#include <memory>
using namespace std;
int mian()
{
shared_ptr<string> sp = unique_ptr<string>(new string("hello"));
//可以将 unique 转换为 shared
}
6. release
虽然我们不能拷贝或赋值 unique_ptr,但可以通过调用 release() 或 reset() 将指针的所有权从一个(非const)unique_ptr 转移给另一个 unique_ptr
#include <iostream>
#include <memory>
using namespace std;
int mian()
{
unique_ptr<string> p1(new string("hello"));
// release()返回p1当前保存的指针,并将p1置为空。p2被初始化为p1原来保存的指针,即将所有权从p1转移给p2
unique_ptr<string> p2(p1.release());
}
但是,如果我们不用另一个智能指针来保存release() 返回的指针,我们的程序就要负责资源的释放,否则就会有内存泄漏
#include <iostream>
#include <memory>
using namespace std;
int mian()
{
unique_ptr<string> p1(new string("hello"));
p1.release(); // 错误,导致内存泄漏
}
7. reset
-
若 reset 不带参数:释放智能指针所指向的对象,并将智能指针置空。
#include <iostream> #include <memory> using namespace std; int mian() { unique_ptr<string> p1(new string("hello")); p1.reset(); }
-
若 reset 带参数:释放智能指针所指向的对象,并让该智能指针指向新对象。
#include <iostream> #include <memory> using namespace std; int mian() { unique_ptr<string> p1(new string("hello")); p1.reset(new string("world")); }
8. = nullptr
#include <iostream>
#include <memory>
using namespace std;
int mian()
{
unique_ptr<string> p(new string("hello"));
p = nullptr;
}
9. get
返回智能指针中保存的指针
#include <iostream>
#include <memory>
using namespace std;
int mian()
{
unique_ptr<string> up(new string("hello"));
string* p = up.get();
*p = "world";
}
10. 定制删除器
可以为 unique_ptr 提供一个自定义的删除器,该删除器会在 unique_ptr 被销毁时调用。
通常在声明std::unique_ptr对象时,可以通过构造函数指定删除器。
void customDeleter(int* ptr) {
// 自定义删除逻辑
delete ptr;
}
std::unique_ptr<int, decltype(&customDeleter)> ptr(new int(5), customDeleter);
举个例子:
#include <iostream>
#include <memory>
using namespace std;
void customDeleter(string* ptr)
{
delete ptr;
ptr = nullptr;
}
int main()
{
// 使用using
using cus_del = void(*)(string*);
unique_ptr<string, cus_del> uni_ptr(new string("hello"),customDeleter);
// 使用 lambda
auto my_del = [](string* ptr)->{
delete ptr;
ptr = nullptr;
}
unique_ptr<string, decltype(my_del)> uni_ptr(new string("hello"),my_del );
}
自定义删除器的类型:函数指针、函数对象或lambda表达式*。通常,使用lambda表达式来定义自定义删除器是比较方便的。
注意:std::make_unique函数不直接支持指定删除器。如果不需要使用删除器,建议使用std::make_unique,因为它通常具有更高的性能。
自定义删除器的应用场景:
- 对于需要特殊处理的资源,如大内存块、缓存等,自定义删除器可以提供更高效的内存管理方式。
- 对于特定资源,如文件句柄、数据库连接等,使用自定义删除器可以确保资源的正确释放和管理。
- 通过使用自定义删除器,std::unique_ptr能够在释放资源时执行特定的清理操作,从而帮助节省内存并提升性能