c++笔记记录2

智能指针

1.不带引用计数的智能指针 auto_ptr ,scoped_ptr,unique_ptr

2.带引用的智能指针 shared_ptr,weak_ptr

智能指针的实现,不能放在堆上,这就变成裸指针,应该在栈上面,这样才能自动释放

template<typename T>
class CSmartPtr
{
public:
 	CSmartPtr(T* ptr=nullptr):mptr(ptr){}
 	~CSmartPtr(){delete mptr;mptr=nullptr;
                }
 	T& operator*(){return *mptr;}
 	T* operator->(){return mptr;}
private:
	T* mptr;
};

3.怎么解决浅拷贝的问题(两个指针指向同一块空间?)

1、不带引用计数的指针 auto_ptr ,scoped_ptr,unique_ptr
	auto_ptr智能指针不带引用计数,那么它处理浅拷贝的问题,是直接把前面的auto_ptr都置为nullptr,只让最后一个auto_ptr持有资源。
	auto _ptr<int>ptr1(new int);
	auto_ptr<int >ptr2(ptr1);, ptr1就是被置空了
	
	scoped_ptr, 不能使用拷贝构造和赋值构造,进行了delete
	该智能指针由于私有化了拷贝构造函数和operator=赋值函数,因此从根本上杜绝了智能指针浅拷贝的发生,
	所以scoped_ptr也是不能用在容器当中的,如果容器互相进行拷贝或者赋值,就会引起scoped_ptr对象的拷贝构造和赋值,
	这是不允许的,代码会提示编译错误。
	
	推荐使用:unique_ptr,也是进行delete	,防止智能指针浅拷贝问题的发生,
	但是多了一个右值引用,对临时变量的拷贝构造赋值
	unique_ptr还提供了reset重置资源,swap交换资源等函数,也经常会使用到。
	可以看到,unique_ptr从名字就可以看出来,最终也是只能有一个该智能指针引用资源,
	因此建议在使用不带引用计数的智能指针时,可以优先选择unique_ptr智能指针。
	unique<int >p1(new int);
	unique<int>p2(std::move(p1)); //没有move失败
	
	
2、带引用计数指针 :多个智能指针可以管理同一个资源,给每个对象资源匹配一个引用计数
	智能指针-》资源的时候=》引用计数加一
	智能指针不使用资源的时候,引用计数-1, =》到0资源释放
	shared_ptr 强智能指针
	weak_ptr 弱智能指针
	weak_ptr(监视)=>shared_ptr(控制)=>资源
	shared_ptr智能指针的资源引用计数器在内存的heap堆上

4.智能指针的交叉引用(循环引用)问题

#include <iostream>
#include <memory>
using namespace std;

class B; // 前置声明类B
class A
{
public:
	A() { cout << "A()" << endl; }
	~A() { cout << "~A()" << endl; }
	shared_ptr<B> _ptrb; // 指向B对象的智能指针
};
class B
{
public:
	B() { cout << "B()" << endl; }
	~B() { cout << "~B()" << endl; }
	shared_ptr<A> _ptra; // 指向A对象的智能指针
};
int main()
{
	shared_ptr<A> ptra(new A());// ptra指向A对象,A的引用计数为1
	shared_ptr<B> ptrb(new B());// ptrb指向B对象,B的引用计数为1
	ptra->_ptrb = ptrb;// A对象的成员变量_ptrb也指向B对象,B的引用计数为2
	ptrb->_ptra = ptra;// B对象的成员变量_ptra也指向A对象,A的引用计数为2

	cout << ptra.use_count() << endl; // 打印A的引用计数结果:2
	cout << ptrb.use_count() << endl; // 打印B的引用计数结果:2

	/*
	出main函数作用域,ptra和ptrb两个局部对象析构,分别给A对象和
	B对象的引用计数从2减到1,达不到释放A和B的条件(释放的条件是
	A和B的引用计数为0),因此造成两个new出来的A和B对象无法释放,
	导致内存泄露,这个问题就是“强智能指针的交叉引用(循环引用)问题”
	*/
	return 0;
}
代码打印结果:
A()
B()
2
2

弱智能指针weak_ptr区别于shared_ptr之处在于:

weak_ptr不会改变资源的引用计数,只是一个观察者的角色,通过观察shared_ptr来判定资源是否存在
weak_ptr持有的引用计数,不是资源的引用计数,而是同一个资源的观察者的计数
weak_ptr没有提供常用的指针操作,无法直接访问资源,需要先通过lock方法提升为shared_ptr强智能指针,才能访问资源

造成new出来的资源无法释放,资源泄露问题

所以我们在定义对象的时候,用强智能指针,引用对象的时候,使用弱智能指针

由于weak_ptr可以不占资源引用计数,也就是解决带引用计数的智能指针的交叉引用问题
在这里插入图片描述

class B; // 前置声明类B
class A
{
public:
	A() { cout << "A()" << endl; }
	~A() { cout << "~A()" << endl; }
	weak_ptr<B> _ptrb; // 指向B对象的弱智能指针。引用对象时,用弱智能指针
};
class B
{
public:
	B() { cout << "B()" << endl; }
	~B() { cout << "~B()" << endl; }
	weak_ptr<A> _ptra; // 指向A对象的弱智能指针。引用对象时,用弱智能指针
};

弱智能指针没有对operator* operator->进行重载
弱指针不能调用,但是可以用lock的方法进行提升为强指针调用

class B{
public:	
	B(){cout<<"B()"<<endl;
	~B(){cout<<"~B()"<<endl;
	void func()
{
	shared_ptr<A>ps=_ptra.lock();//提升方法
	if(ps!=nullptr){
		ps->testA();//提升后就可以调用访问资源
		}
}
	weak_ptr<A>_ptra;
};

5.多线程访问共享对象问题

线程A和线程B访问一个共享的对象,如果线程A正在析构这个对象的时候,线程B又要调用该共享对象的成员方法,此时可能线程A已经把对象析构完了,线程B再去访问该对象,就会发生不可预期的错误。借助shared_ptr和weak_ptr解决了这样一个问题,多线程访问共享对象的线程安全问题

void threadProc(weak_ptr<Test> pw) // 通过弱智能指针观察强智能指针
{
	// 睡眠两秒
	std::this_thread::sleep_for(std::chrono::seconds(2));
	/* 
	如果想访问对象的方法,先通过pw的lock方法进行提升操作,把weak_ptr提升
	为shared_ptr强智能指针,提升过程中,是通过检测它所观察的强智能指针保存
	的Test对象的引用计数,来判定Test对象是否存活,ps如果为nullptr,说明Test对象
	已经析构,不能再访问;如果ps!=nullptr,则可以正常访问Test对象的方法。
	*/
	shared_ptr<Test> ps = pw.lock();
	if (ps != nullptr)
	{
		ps->show();
	}
}
int main()
{
	// 在堆上定义共享对象
	shared_ptr<Test> p(new Test);
	// 使用C++11的线程,开启一个新线程,并传入共享对象的弱智能指针
	std::thread t1(threadProc, weak_ptr<Test>(p));
	// 在main线程中析构Test共享对象
	// 等待子线程运行结束
	t1.join();
	return 0;
}

6.智能指针的删除器deletor

class FileDeleter
{
public:
	// 删除器负责删除资源的函数
	void operator()(FILE *pf)
	{
		fclose(pf);
	}
};
int main()
{
    // 由于用智能指针管理文件资源,因此传入自定义的删除器类型FileDeleter
	unique_ptr<FILE, FileDeleter> filePtr(fopen("data.txt", "w"));
	return 0;
}

也可以通过下面方式:

  1. function(函数对象)保存函数的三个方式:保存普通函数、保存lambda表达式、保存成员函数;但是重载的成员函数需要配合bind才可以。
  2. bind(绑定器)的目的:不同的任务能传递不同的参数。

// 自定义智能指针删除器,关闭文件资源

unique_ptr<FILE, function<void(FILE*)>>
		filePtr(fopen("data.txt", "w"), [](FILE *pf)->void{fclose(pf);});

// 自定义智能指针删除器,释放数组资源

unique_ptr<int, function<void(int*)>>
		arrayPtr(new int[100], [](int *ptr)->void {delete[]ptr; });
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值