C++ —— 智能指针:std::unique_ptr

简介

     智能指针是一种特殊的指针类型,它能够自动管理内存资源,避免常见的内存泄漏和多次释放等。在C++ 11标准中出现了新的智能指针unique_ptr、 shared_ptr、weak_ptr等。

std::unique_ptr

     用于管理动态分配的内存资源,它提供了自动释放内存的功能。与原始指针相比,unique_ptr有更高的安全性和易用性。

     特点: 所有权唯一、自动释放内存、指针语义、禁止拷贝和权限转移、自定义删除器

          所有权唯一:每个unique_ptr实例拥有对其所指向对象的唯一所有权。这意味着在任何时候只有一个unique_ptr可以指向一个特定的对象。

          自动释放内存:当unique_ptr超出作用域或被重新赋值时,它所管理的内存会自动释放。这样就避免了内存泄漏的问题。

          指针语义:使用方式与原始指针相似,可通过指针操作符(->)和解引用操作符(*)来访问所指向对象成员。

          禁止拷贝:unique_ptr禁止拷贝,即不能进行复制构造和赋值操作。这是为了确保独占所有权的特性,防止多个指针同时管理同一个对象的内存。

          权限转移:支持移动构造和移动赋值操作,将所有权转移给新的unique_ptr而旧指针则自动释放置空,无需进行内存拷贝。

          自定义删除器:unique_ptr可通过模板参数来指定一个删除器(deleter)函数对象,用于在释放内存时执行额外的清理操作。

     缺点: 使用裸指针赋值或捕获会很容易非常的乱、导致内存泄露,尽量避免智能指针和普通指针的混合。


     常见成员函数:

常见成员函数:
	operator*	解引用操作符,用于获取 unique_ptr 所指向对象的引用。
	operator->	箭头操作符,用于通过 unique_ptr 访问对象的成员函数或成员变量。
	get			返回指向所管理对象的裸指针。
	reset		重置 unique_ptr,释放当前所管理的对象并接管新的对象。
	release		释放对所管理对象的控制权,并返回该指针的裸指针。
	swap		交换两个 unique_ptr 的内容。


     示例测试:

          基本操作1

#include <iostream>

void unique_operate1()
{
   
	/******************** 创建 ********************/
	// 创建方式一,初始化后修改值
	std::unique_ptr<int> pInt1(new int(10));
	*pInt1 = 101;

	// 创建方式二,初始化后修改值
	std::unique_ptr<int> pInt2 = std::unique_ptr<int>(new int(20));
	*pInt2 = 102;

	// 创建方式三,初始化后修改值
	std::unique_ptr<int> pInt3 = std::make_unique<int>(30);
	*pInt3 = 103;

	// 创建多个int指针对象,初始化后修改值
	std::unique_ptr<int[]> pIntArray(new int[5]{
    10,20,30,40,50 });
	pIntArray[0] = 1;
	pIntArray[1] = 2;
	pIntArray[2] = 3;
	pIntArray[3] = 4;
	pIntArray[4] = 5;
	/*********************************************/

	/******************** 输出地址及值 ********************/
	std::cout << pInt1 << " " << *pInt1 << " | " << pInt1.get() << " " << *(pInt1.get()) << std::endl;
	std::cout << pInt1 << " " << *pInt1 << " | " << pInt1.get() << " " << *(pInt1.get()) << std::endl;
	std::cout << pInt1 << " " << *pInt1 << " | " << pInt1.get() << " " << *(pInt1.get()) << std::endl;

	/*
	输出为:
		000002110F242540 101 | 000002110F242540 101
		000002110F242540 101 | 000002110F242540 101
		000002110F242540 101 | 000002110F242540 101
	*/
	/*********************************************/

	/******************** 权限转移 ********************/
	std::cout << pInt1 << " " << *pInt1 << std::endl;
	//std::unique_ptr<int> P1 = pInt1;			// 错误操作
	std::unique_ptr<int> P1 = std::move(pInt1);	// 正确操作。此时P1接收了pInt1的地址和值,而pInt1则被置空
	std::cout << P1 << " " << *P1 << std::endl;

	/*
	注意:
		pInt1由于被置空,此时无法使用否则出现异常。

	输出为:
		000002303C431670 101
		000002303C431670 101
	*/
	/*********************************************/
}

int main()
{
   
	// 基本操作1
	unique_operate1();
	
	return 0;
}


          基本操作2

#include <iostream>

class Operate2
{
   
public:
	Operate2()
	{
   
		std::cout << "call Operate2() \t" << this << std::endl;
	}
	Operate2(const Operate2 &)
	{
   
		std::cout << "call Operate2(const Operate2 &) \t" << this << std::endl;
	}
	~Operate2()
	{
   
		std::cout << "call ~Operate2() \t" << this << std::endl;
	}
	Operate2* operator +(int v)
	{
   
		std::cout << "call operator +  \t" << this << std::endl;
		Operate2 *tmp = new Operate2;
		tmp->value = value + v;
		return tmp;
	}

	// 设置value值
	void setValue(const int &v){
    value = v; }

	// 获取value值
	int getValue()const {
    return value; }

private:
	int value = 10;
};

void unique_operate2()
{
   
	// 进入一次Operate2构造(ptr1)
	std::unique_ptr<Operate2> ptr1 = std::make_unique<Operate2>();

	/******************** 成员操作 ********************/
	// 测试
	std::cout << "print ptr1 ptr add:" << ptr1 << std::endl << std::endl;

	// 测试 ->
	std::cout << "print ptr2 - value is:" << ptr1->getValue() << std::endl;
	ptr1->setValue(20);
	std::cout << "print ptr2 - value is:" << ptr1->getValue() << std::endl << std::endl;

	// 测试 get	:返回指向所管理对象的裸指针
	Operate2 *tOperate2Ptr = ptr1.get();
	std::cout << "tOperate2Ptr - value is:" << ptr1->getValue() << std::endl << std::endl;

	/*
		测试 reset :该方法可让unique_ptr解除对原始内存管理,也可初始化一个独占的智能指针
			reset()				解除对原始内存的管理
			reset(new xxx())	重新指定智能指针管理的原始内存
	*/
	ptr1.reset(new Operate2());					// 新创建的进入一次构造,然后之前的对象进入一次析构
	std::cout << "new print ptr2 - value is:" << ptr1->getValue() << std::endl << std::endl;

	// 测试 release	:释放对所管理对象的控制权,并返回该指针的裸指针
	Operate2 *ttOperate2Ptr = ptr1.release();	// ptr1被置空
	if (ttOperate2Ptr) {
    delete ttOperate2Ptr; }ttOperate2Ptr = nullptr;
	std::cout << std::endl;

	// 测试 swap	:交换两个unique_ptr的内容
	std::unique_ptr<Operate2> Operate2_1 = std::make_unique<Operate2>(); Operate2_1->setValue(6);
	std::unique_ptr<Operate2> Operate2_2 = std::make_unique<Operate2>(); Operate2_2->setValue(9);
	std::cout << "Operate2_1:" << Operate2_1->getValue() << " Operate2_2:" << Operate2_1->getValue() << std::endl;
	Operate2_1.swap(Operate2_2);
	std::cout << "Operate2_1:" << Operate2_1->getValue() << " Operate2_2:" << Operate2_1->getValue() << std::endl;
	/*********************************************/

	// 函数结束,进入一次Operate2析构(ptr1)
}

int main()
{
   
 	// 基本操作2
 	unique_operate2();

	/*
	输出为:
		call Operate2()         0000029218F50140
		print ptr1 ptr add:0000029218F50140
	
		print ptr2 - value is:10
		print ptr2 - value is:20
	
		tOperate2Ptr - value is:20
	
		call Operate2()         0000029218F501C0
		call ~Operate2()        0000029218F50140
		new print ptr2 - value is:10
	
		call ~Operate2()        0000029218F501C0
	
		call Operate2()         0000029218F50140
		call Operate2()         0000029218F501C0
		Operate2_1:6 Operate2_2:6
		Operate2_1:9 Operate2_2:9
		call ~Operate2()        0000029218F50140
		call ~Operate2()        0000029218F501C0
	*/
	return 0;
}


          基本操作3

#include <iostream>

class TestClass
{
   
public:
	TestClass()
	{
   
		std::cout << "call TestClass() \t" << this << std::endl;
	}
	TestClass(const TestClass &)
	{
   
		std::cout << "call TestClass(const TestClass &) \t" << this << std::endl;
	}
	~TestClass()
	{
   
		std::cout << "call ~TestClass() \t" << this << std::endl;
	}
	TestClass* operator +(int v)
	{
   
		std::cout << "call TestClass +  \t" << this << std::endl;
		TestClass *tmp = new TestClass;
		tmp->value = value + v;
		return tmp;
	}

	// 设置value值
	void setValue(const int &v){
    value = v; }

	// 获取value值
	int getValue()const {
    return value; }

private:
	int value = 100;
};


std::unique_ptr<TestClass> changeValue_add10(std::unique_ptr<TestClass> tcPtr)
{
   
	tcPtr->setValue(tcPtr->getValue() + 10);
	return tcPtr;
}

void unique_operate3()
{
   
	std::unique_ptr<TestClass> tcPtr1 = std::make_unique<TestClass>();
	if (tcPtr1) {
    std::cout << "11111:\t" << "ptr:" << tcPtr1 << " *ptr:" << tcPtr1->getValue() << std::endl; }
	//changeValue_add10(stcPtr1);	// 错误:由于unique_ptr不能拷贝,故不得作为形参进行拷贝给实参
	std::unique_ptr<TestClass> tcPtr2 = changeValue_add10(std::move(tcPtr1));
	if (tcPtr2) {
    std::cout << "22222:\t" << "ptr:" << tcPtr2 << " *ptr:" << tcPtr2->getValue() << std::endl; }
}

int main()
{
   
	// 基本操作3
	unique_operate3();

	/*
	输出为:
		call TestClass()        000001F354580A60
		11111:  ptr:000001F354580A60 *ptr:100
		22222:  ptr:000001F354580A60 *ptr:110
		call ~TestClass()       000001F354580A60
	*/
	return 0;
}

关注

笔者 - jxd

相关推荐

  1. C++ 智能指针

    2024-02-04 21:16:01       29 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-04 21:16:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-04 21:16:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-04 21:16:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-04 21:16:01       18 阅读

热门阅读

  1. 【协议学习】38331 测量相关

    2024-02-04 21:16:01       28 阅读
  2. 获取Webshell的一些思路

    2024-02-04 21:16:01       29 阅读
  3. C语言:简单排序

    2024-02-04 21:16:01       30 阅读
  4. Chapter 8 - 4. Congestion Management in TCP Storage Networks

    2024-02-04 21:16:01       31 阅读
  5. 力扣:77. 组合

    2024-02-04 21:16:01       29 阅读
  6. sql数据库修复资料

    2024-02-04 21:16:01       22 阅读
  7. 题目 1159: 偶数求和

    2024-02-04 21:16:01       25 阅读
  8. 海量微服务关联关系挖掘与告警拓扑展示

    2024-02-04 21:16:01       27 阅读