C++智能指针,RAII(资源获取即初始化) 原则

转载:C++ RAII机制详解

转载:C++share_ptr智能指针的使用

中文标准库:RAII

一、unique_ptr

中文标准库:unique_ptr

尽量使用unique_ptr替代裸指针

一个unique_ptr独享它指向的对象,不能直接(使用reset才可以)将一个unique_ptr赋值给其他变量,不过shared_ptr可以。也就是说,同时只有一个unique_ptr指向同一个对象,当这个unique_ptr被销毁时,指向的对象也随即被销毁。如果一个类中包含unique_ptr,那么该类也不能使用拷贝和赋值。

数组版本

std::unique_ptr<int[]> ptr = std::make_unique<int[]>(5); //相当于 int ptr[5] = {0};

局部智能指针不能作为函数返回值,因为智能指针的作用域有限

指针

1. 获取裸指针 get()

返回指向被管理对象的指针

2. 替换被管理对象 reset()

注意:因为一个unique_ptr独享它指向的对象,因此替换被管理的对象时必须释放之前对象的所有权

std::unique_ptr<int> p1 = std::make_unique<int>(2);
std::unique_ptr<int> p2 = std::make_unique<int>(3);
p1 = p2;//错误
p1.reset(p2); //错误
p1.reset(p2.release()); //正确,此时p1管理的是大小为3的int数组对象

3. 释放被管理对象 release()

unique_ptr被销毁时(如离开作用域),对象也就自动释放了,也可以通过其他方式下显式释放对象。如:

up = nullptr; //置为空,释放up指向的对象
up.release(); //放弃控制权,返回裸指针,并将up置为空
up.reset();   //释放up指向的对象

release不会调用析构,只是释放控制权

4. std::unique_ptr和类的前置声明

//test.h
class A;
class B
{
  std::unique<A> m_a;
};

智能指针和类的前置声明

VS报错:can't delete an incomplete type 解决方法:将类的构造函数和析构函数在cpp文件中实现。如果这个类还包含了一个前置声明的类,将这个前置声明的类的头文件包含到cpp文件(A包含了B,B包含了C,需要在A.cpp包含C.h)。

二、share_ptr

尽量少用share_ptr

shared_ptr是支持共享所有权的引用计数型指针,“共享”指的是允许多个指针指向同一个资源,shared_ptr对象可以被拷贝与赋值,“引用计数”指的是它可以记录当前指向同一资源的指针的数量, 当计数为0的时候才会释放动态分配的对象。对shared_ptr循环引用会导致因为无法释放资源引发的内存泄漏。典型的如双链表。不要把一个裸指针给多个shared_ptr对象管理

#include <iostream>
#include <memory>

class B;

class A
{
public:
	A() = default;
	~A() { std::cout << "~A\n"; }

	std::shared_ptr<B> _b;
};

class B
{
public:
	B() = default;
	~B() { std::cout << "~B\n"; }

	std::shared_ptr<A> _a;
};


int main()
{
	auto pa = std::make_shared<A>();
	auto pb = std::make_shared<B>();

	pa->_b = pb;
	pb->_a = pa;

	std::cout << "A use count:" << pa.use_count() << std::endl; 
	std::cout << "B use count:" << pb.use_count() << std::endl;
}

输出如下

A use count:2
B use count:2

因为引用计数都是2,所以在main函数结束的时候,不会调用类A和类B的析构函数,就出现了内存泄漏。上面产生内存泄漏的原因,就是我们常说的循环引用

三、weak_ptr

weak_ptr就是为了辅助shared_ptr的,它本身不能直接指向原生指针对象,只能指向shared_ptr对象。

weak_ptr总结

  • weak_ptr虽然是一个模板类,但是不能用来直接定义指向原始指针的对象。

  • weak_ptr接受shared_ptr类型的变量赋值,但是反过来是行不通的,需要使用lock函数。

  • weak_ptr设计之初就是为了服务于shared_ptr的,所以不增加引用计数就是它的核心功能。

  • 由于不知道干了什么之后weak_ptr所指向的对象就会被析构掉,所以使用之前请先使用expired函数检测一下。

转载:智能指针(3):weak_ptr浅析

四、auto_ptr

被摒弃 https://www.cnblogs.com/lanxuezaipiao/p/4132096.html

示例代码

点击查看代码
#include <iostream>
#include <memory>

class A
{
public:
	std::shared_ptr<int> sharedInt = std::make_shared<int>(1);
	//std::unique_ptr<int> uniqueInt = std::make_unique<int>(2);
	void show() { std::cout << *sharedInt << "\n"; }
};

int main()
{
	A a;
	a.show();
	A a1 = a;  //如果类A中有unique_ptr报错
	A a2 = a1;

	std::cout << a.sharedInt.use_count();  //3

	///< Shared_ptr
	auto s1 = std::make_shared<int>(1);
	auto s2 = std::make_shared<int>(2);
	auto s3 = std::make_shared<int>(3);

	std::shared_ptr<int> ps1;
	std::shared_ptr<int> ps2;
	auto c1 = s1.use_count(); //1
	auto c2 = s2.use_count(); //1
	auto c3 = s3.use_count(); //1
	auto c4 = ps1.use_count(); //0
	auto c5 = ps2.use_count(); //0

	ps1 = s1;  //共享s1指向的对象(unique_ptr不支持)
	auto c6 = ps1.use_count(); //2
	auto c7 = s1.use_count(); //2
	ps2 = s1;
	auto c8 = s1.use_count(); //3
	auto c9 = ps2.use_count(); //3


	///< unique_ptr
	std::unique_ptr<int> pu1 = std::make_unique<int>(2);
	std::unique_ptr<int> pu2 = std::make_unique<int>(3);
	//p1.reset(p2); //错误
	//std::unique_ptr<int> pu6 = pu1; //错误,因为unique_ptr独享它指向的对象(可以用shared_ptr共享)
	pu1.reset(pu2.release()); //正确,此时p1管理的是值为3的int指针

	auto pu1Value1 = *pu1.get();

	std::unique_ptr<int[]> pu3 = std::make_unique<int[]>(9);  //大小为9的int数组
	std::unique_ptr<int[]> pu4 = std::unique_ptr<int[]>(new int[3]); //大小为3的int数组,不推荐使用new

	std::unique_ptr<int[]> pu5;

	int arr[5] = { 0 };
	int* pu6 = new int[8];
	pu4.reset(arr);
	pu5.reset(pu6);

	//std::unique_ptr<int[]> pu7(pu3);  //错误
	std::unique_ptr<int[]> pu7(std::move(pu3));//正确

	//pu5.reset(std::move(pu3));  //错误
	//pu4.reset(pu3); //错误
	pu5.reset(pu3.release()); //正确
	
	(*pu1) = 99;  //给pu1赋值
	auto pu1Value2 = *pu1;


	system("pause");
	return 0;
}
posted @ 2021-03-10 16:59  滴哒哒哒  阅读(82)  评论(0编辑  收藏  举报