unique_ptr的常用操作详解——(C++11智能指针)

🎖  博主的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_ptrC++ 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能够在释放资源时执行特定的清理操作,从而帮助节省内存并提升性能
  • 19
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ryan.Alaskan Malamute

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值