IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> (笔记C++)第二十六节课:智能指针 -> 正文阅读

[C++知识库](笔记C++)第二十六节课:智能指针

一 智能指针

1.1 手动初始化

注意:share_ptr<int> p = new int(10); //错误
share_ptr是explicit,不能进行隐式类型转换,只能直接初始化

1.1.1 make_shared

?

    //功能:在堆区可以动态分配对象,并返回一个share_ptr(推荐,安全,高效)(构造方法初始化)
    auto p = std::make_shared<string>("helloworld");
?
    shared_ptr<int> p1 = make_shared<int>(5);
    cout << *p1 << endl;
    shared_ptr<string> ps = make_shared<string>("hello world");
    cout << *ps << endl;
    //手动初始化和使用make_shared函数模板初始化有什么区别?
    //开销小,效率高(数据和引用计数存在同一个空间)
    //构造函数初始化:数据和引用计数不再同一段空间,需要间接访问
?
    shared_ptr<A> a1 = make_shared<A>();
    shared_ptr<A> a2(a1);

1.2 常规操作

1.2.1 use_count()

功能:返回有多少个智能指针指向某个对象(引用计数的个数)
用途:主要用于调试
shared_ptr<A> a1 = make_shared<A>();
shared_ptr<A> a2(a1);
cout << a2.use_count() << endl; ?//返回当前有多少个指针指向当前对象或者空间

1.2.2 unique();

功能:是否该智能指针独占某个对象,独占返回true,否则返回false;
if (a1.unique()) ?//判断当前指针是否独享(只有它自己指向该对象)或者空间
    {
        cout << "a1 is unique ptr" << endl;
    }

1.2.3 reset

功能:判断当前指针是否独享该对象,如果独享,则释放该对象,否则将该指针置为NULL,并将引用计数器减一
用法:reset()或者reset(参数)
//判断当前指针是否独享该对象,如果独享,则释放该对象,并使该指针指向形参所对应的空间
    a1.reset(new A(10));
    //shared_ptr<A> pa(new A(188));
    //a1.reset(pa);
    cout << a1->m_a << endl;

1.2.4 解引用

获取智能指针指向的对象,并对其操作
get(); //获取智能指针中保存的裸指针。
shared_ptr<int> pd = make_shared<int>(5);
Test(pd.get());

1.2.5 指定删除器

功能:有些情况,默认删除器处理不了(share_ptr管理的动态数组)
 需要我们自己指定删除器,调用删除器函数释放空间
//指定删除器:当删除器不起作用的时候,需要自己指定删除器 void(*)(T*)
//shared_ptr<A> pa(new A[3]);  //delete pa --->应该是delete []pa;
//shared_ptr<A[]> pa(new A[3]);
//shared_ptr<A> pa(new A[3], Mydelete);
shared_ptr<A> pa(new A[3], default_delete<A[]>());

1.2.6 lambda 表达式

shared_ptr<A> pa(new A[3], [](A*a) {
		delete[]a;    //lambda表达式
	});

1.2.7 移动语义

shared_ptr<A> pa(new A(5));
	const shared_ptr<A> &rpa = move(pa);
	//shared_ptr<A> &&rpa = move(pa);
	cout << "***************"<<endl;
	//pa = nullptr;
	cout << pa.use_count() << endl;
	cout << rpa.use_count() << endl;
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class A
{
public:
	A()
	{
		cout << "A的无参构造" << endl;
	}
	A(int n)
	{
		m_a = n;
		cout << "A的有参构造" << endl;
	}
	
	~A()
	{
		cout << "A的析构函数" << endl;
	}
public:
	int m_a;
};
shared_ptr<A> test()
{
	shared_ptr<A> temp(new A);
	return temp;
}
void Func(shared_ptr<A> temp)
{
	cout << temp->m_a << endl;
}
void Test(int *p)
{

}
void Mydelete(A *pa)
{
	delete[]pa;
}
int main(void)
{
#if 0
	//int *p = new int(5);  //p是裸指针
	//shared_ptr<int> p = new int(5); //初始化:调用类型转换构造函数 explicit
	shared_ptr<int> p(new int(5));
	cout << *p << endl;

	shared_ptr<string> s(new string("helloworld"));
	cout << *s << endl;
	int num = 100;
	//shared_ptr<int> p2(&num);   //智能指针常用于堆空间,指向栈空间的时候,会导致内存释放两次

	 //A *pa = new A(100);
	//delete pa;
	shared_ptr<A> pa(new A);
	shared_ptr<A> res = test();
	Func(pa);
	shared_ptr<A> pa2(pa);

	//功能:在堆区可以动态分配对象,并返回一个share_ptr(推荐,安全,高效)(构造方法初始化)
	auto p = std::make_shared<string>("helloworld");

	shared_ptr<int> p1 = make_shared<int>(5);
	cout << *p1 << endl;
	shared_ptr<string> ps = make_shared<string>("hello world");
	cout << *ps << endl;
	//手动初始化和使用make_shared函数模板初始化有什么区别?
	//开销小,效率高(数据和引用计数存在同一个空间)
	//构造函数初始化:数据和引用计数不再同一段空间,需要间接访问

//常规操作:
	shared_ptr<A> a1 = make_shared<A>();
	shared_ptr<A> a2(a1);
	cout << a2.use_count() << endl;  //返回当前有多少个指针指向当前对象或者空间

	if (a1.unique())  //判断当前指针是否独享(只有它自己指向该对象)或者空间
	{
		cout << "a1 is unique ptr" << endl;
	}

	a1.reset();
	if (a1 == nullptr)  //NULL:void*()   0
	{
		cout << "a1 is nullptr" << endl;
	}
	cout << a2.use_count() << endl;
	//判断当前指针是否独享该对象,如果独享,则释放该对象,并使该指针指向形参所对应的空间
	a1.reset(new A(10));
	//shared_ptr<A> pa(new A(188));
	//a1.reset(pa);
	cout << a1->m_a << endl;

	shared_ptr<int> pd = make_shared<int>(5);
	Test(pd.get());
#endif
	//指定删除器:当删除器不起作用的时候,需要自己指定删除器 void(*)(T*)
	//shared_ptr<A> pa(new A[3]);  //delete pa --->应该是delete []pa;
	//shared_ptr<A[]> pa(new A[3]);
	//shared_ptr<A> pa(new A[3], Mydelete);
	//shared_ptr<A> pa(new A[3], default_delete<A[]>());
	/*shared_ptr<A> pa(new A[3], [](A*a) {
		delete[]a;    //lambda表达式
	});*/
	shared_ptr<A> pa(new A(5));
	const shared_ptr<A> &rpa = move(pa);
	//shared_ptr<A> &&rpa = move(pa);
	cout << "***************"<<endl;
	//pa = nullptr;
	cout << pa.use_count() << endl;
	cout << rpa.use_count() << endl;
	return 0;
}

1.3 auto_ptr

#include <iostream>
#include <memory>
using namespace std;
class Test 
{
public:
	Test()
	{
		cout << "Test的构造函数" << endl;
	}
	void print()
	{
		cout << "hello world" << endl;
	}
	~Test()
	{
		cout <<"Test的析构函数"<<endl;
	}
};
void func1()
{
	Test *pt = new Test;
}
void func2()
{
	auto_ptr<Test> pt(new Test);
	pt->print();  //pt.operator->(print());
}
int main(void)
{
	func2();
	func2();
}

1.4 weak_ptr

1.4.1 概念

弱指针:不会控制对象的生命周期(不会改变对象的引用计数)。
share_ptr释放指向对象时,是不会考虑weak_ptr是否指向该对象。
weak_ptr不是独立指针,不能单独操作所指向的资源。

1.4.2 作用

weak_ptr指针一般用来辅助share_ptr的使用(监视share_ptr指向对象的生命周期)
weak_ptr和share_ptr可以相互转化,share_ptr可以直接赋值给weak_ptr
但是反过来是行不通的,需要使用lock函数。

1.4.3 常规操作

(1)lock函数

调用Lock函数用来获取share_ptr(如果对象已经被释放,则返回一个空的share_ptr)
shared_ptr<A> pa(new A(5));
pa.reset();
weak_ptr<A> wpa = pa;
auto pb = wpa.lock();  //将弱指针转为共享指针
if(nullptr == pb)
{
    cout << "pb is nullptr" << endl;
}
else
{
    cout << "pb is not nullptr" << endl;
}

(2)use_count

功能:返回有多少个weak_ptr智能指针指向对象(引用计数的个数)
用途:主要用于调试。

(3)expired

功能:判断弱指针是否过期(所检测的对象是否被释放 true /false)
//wpa.reset();  //弱引用计数-1,
cout << wpa.use_count() << endl;  //返回的是weak_ptr的引用计数
cout << pb.use_count() << endl;
if (wpa.expired())    //判断当前弱指针指向的对象是否被释放,弱被释放,返回true,否则返回false
{
    cout << "wpa poniter class is free" << endl;
}

(4) 循环引用

?

#include <iostream>
#include <memory>
#include <string>
using namespace std;
class Child;
class Parent;
class A
{
public:
	A()
	{
		cout << "A的无参构造" << endl;
	}
	A(int n)
	{
		m_a = n;
		cout << "A的有参构造" << endl;
	}
	
	~A()
	{
		cout << "A的析构函数" << endl;
	}
public:
	int m_a;
};
class Parent
{
public:	
	Parent()
	{
		cout << "Parent的构造函数" << endl;
	}
	~Parent()
	{
		cout << "parent的析构函数" << endl;
	}
	weak_ptr<Child> c;
};
class Child :public Parent
{
public:
	Child()
	{
		cout << "Child的构造函数" << endl;
	}
	~Child()
	{
		cout << "Child的析构函数" << endl;
	}
	weak_ptr<Parent> p;
};

int main(void)
{
#if 0
	//weak_ptr<A> wpa(new A(5));  //不能独立操作一块空间

	shared_ptr<A> pa(new A(5));
	//weak_ptr:类模板,弱指针(弱引用计数)
	weak_ptr<A> wpa = pa; 
	
	weak_ptr<A> wpb = pa;
	weak_ptr<A> wpc = pa;  //弱引用不会影响其生命周期,无论多少个弱引用指向这段空间,只要强引用计数为0,则释放这段空间

	//常规操作:
	shared_ptr<Parent> pp(new Parent);
	shared_ptr<Child> cc(new Child);
	pp->c = cc;
	cc->p = pp;
	cout << "hello world" << endl;
#endif
	shared_ptr<A> pa(new A(5));
	//pa.reset();
	weak_ptr<A> wpa = pa;
	auto pb = wpa.lock();  //将弱指针转为共享指针
	if(nullptr == pb)
	{
		cout << "pb is nullptr" << endl;
	}
	else
	{
		cout << "pb is not nullptr" << endl;
	}
	//wpa.reset();  //弱引用计数-1,
	cout << wpa.use_count() << endl;  //返回的是weak_ptr的引用计数
	cout << pb.use_count() << endl;
	if (wpa.expired())    //判断当前弱指针指向的对象是否被释放,弱被释放,返回true,否则返回false
	{
		cout << "wpa poniter class is free" << endl;

	}
	return 0;
}

(5) share_ptr & weak_ptr

尺寸:share_ptr 和 weak_ptr一样大,都是裸指针的两倍

?

#include <iostream>
#include <memory>
#include <string>
using namespace std;
class Child;
class Parent;
class A:public enable_shared_from_this<A>
{
public:
	A()
	{
		cout << "A的无参构造" << endl;
	}
	A(int n)
	{
		m_a = n;
		cout << "A的有参构造" << endl;
	}
	//A *GetAddr()
	shared_ptr<A> GetAddr()
	{
		//return this;
		//shared_ptr<A> tmp(this);
		//return tmp;
		//实现原理:
			//其内部有一个weak_ptr类型的成员变量_wptr
			//当shared_ptr构造的时候,如果其模板类型继承了enable_shared_from_this<T>,则堆_wptr进行初始化操作
			//这样在调用shared_from_this()的时候,就能通过weak_ptr构造出对应的shared_ptr
		return shared_from_this();  //和pa共享其所有权
	}
	~A()
	{
		cout << "A的析构函数" << endl;
	}
public:
	int m_a;
};
class Parent
{
public:	
	Parent()
	{
		cout << "Parent的构造函数" << endl;
	}
	~Parent()
	{
		cout << "parent的析构函数" << endl;
	}
	weak_ptr<Child> c;
};
class Child :public Parent
{
public:
	Child()
	{
		cout << "Child的构造函数" << endl;
	}
	~Child()
	{
		cout << "Child的析构函数" << endl;
	}
	weak_ptr<Parent> p;
};

int main(void)
{
#if 0
	//weak_ptr<A> wpa(new A(5));  //不能独立操作一块空间

	shared_ptr<A> pa(new A(5));
	//weak_ptr:类模板,弱指针(弱引用计数)
	weak_ptr<A> wpa = pa; 
	
	weak_ptr<A> wpb = pa;
	weak_ptr<A> wpc = pa;  //弱引用不会影响其生命周期,无论多少个弱引用指向这段空间,只要强引用计数为0,则释放这段空间

	//常规操作:
	shared_ptr<Parent> pp(new Parent);
	shared_ptr<Child> cc(new Child);
	pp->c = cc;
	cc->p = pp;
	cout << "hello world" << endl;

	shared_ptr<A> pa(new A(5));
	//pa.reset();
	weak_ptr<A> wpa = pa;
	auto pb = wpa.lock();  //将弱指针转为共享指针
	if(nullptr == pb)
	{
		cout << "pb is nullptr" << endl;
	}
	else
	{
		cout << "pb is not nullptr" << endl;
	}
	//wpa.reset();  //弱引用计数-1,
	cout << wpa.use_count() << endl;  //返回的是weak_ptr的引用计数
	cout << pb.use_count() << endl;
	if (wpa.expired())    //判断当前弱指针指向的对象是否被释放,弱被释放,返回true,否则返回false
	{
		cout << "wpa poniter class is free" << endl;

	}

	shared_ptr<int> p(new int(5));
	cout << sizeof(p) << endl;
	cout << sizeof(int *) << endl;

	weak_ptr<int> wp = p;
	cout << sizeof(wp) << endl;
#endif
	//局部对象释放两次,A自己释放一次,share_ptr还会释放一次
	/*A a;
	shared_ptr<A> tmp = a.GetAddr();*/
/*
	shared_ptr<A> GetAddr()
	{
		//return this;
		shared_ptr<A> tmp(this);
		return tmp;
	}
*/
	shared_ptr<A> pa(new A());
	auto tmp = pa->GetAddr();
	cout << pa.use_count() << endl;
	cout << tmp.use_count() << endl;
    
    int * pt = new int();
	shared_ptr<int> spt1(pt);
	shared_ptr<int> spt2(pt);
	std::cout << "spt1.use_count() = " << spt1.use_count() << std::endl;
	std::cout << "spt2.use_count() = " << spt2.use_count() << std::endl;
	return 0;
}

1.4.4 总结

优点:防止内存泄漏
缺点:造成不必要的开销
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-07-17 16:02:42  更:2022-07-17 16:05:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/13 22:25:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码