智能指针简单总结

本文介绍了C++标准库中的四种智能指针(auto_ptr、unique_ptr、shared_ptr和weak_ptr),重点阐述了它们如何管理和释放动态内存,以及各自的特点和应用场景,特别是unique_ptr的排他所有权和shared_ptr的共享所有权机制。
摘要由CSDN通过智能技术生成

C++标准库提供了四种智能指针:auto_ptr、unique_ptr、shared_ptr 和weak_ptr

  1. C++98 提供了 auto_ptr 模板的解决方案
  2. C++11 增加unique_ptr、shared_ptr 和weak_ptr

使用智能指针的目的是为了更安全,更容易的管理动态内存。

     在c++中,动态内存的管理式通过一对运算符来完成的:new,在动态内存中为对象分配空间并返回一个指向该对象的指针,我们可以选择对对象进行初始化;delete,接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。动态内存的使用很容易出现问题,因为确保在正确的时间释放内存是极其困难的。有时使用完对象后,忘记释放内存,造成内存泄漏的问题。

      智能指针本质就是一个类模板,它可以创建任意的类型的指针对象,当智能指针对象使用完后,对象就会自动调用析构函数去释放该指针所指向的空间

一、auto_ptr

auto_ptr是c++98版本库中提供的智能指针,该指针解决上诉的问题采取的措施是管理权转移的思想,也就是原对象拷贝给新对象的时候,原对象就会被设置为nullptr,此时就只有新对象指向一块资源空间。

一个auto_ptr p1指针指向一块new出来的空间,p1给另一个智能指针赋值,p2会接管p1的所有权,如果此时再去操作p1这个对象的时候,程序会崩溃。 

 如果auto_ptr调用拷贝构造函数或者赋值重载函数后,如果再去使用原来的对象的话,那么整个程序就会崩溃掉(因为原来的对象被设置为nullptr),这对程序是有很大的伤害的.所以很多公司会禁用auto_ptr智能指针。 

二、unique_ptr

unique_ptr同auto_prt一样也是采用所有权模式,即同一时间只能有一个智能指针可以指向这个对象,但之所以unique_ptr智能指针更加安全,是因为它相比于auto_pr而言禁止了拷贝操作,unique_ptr采用了移动赋值std::move()函数来进行控制权的转移。

特性:

  1. 基于排他所有权模式:两个指针不能指向同一个资源
  2. 无法进行左值unique_ptr复制构造,也无法进行左值复制赋值操作,但允许临时右值赋值构造和赋值
  3. 保存指向某个对象的指针,当它本身离开作用域时会自动释放它指向的对象。
unique_ptr<string> p1(new string("I'm Li Ming!"));
unique_ptr<string> p2(new string("I'm age 22."));
	
cout << "p1:" << p1.get() << endl;
cout << "p2:" << p2.get() << endl;

p1 = p2;					// 禁止左值赋值
unique_ptr<string> p3(p2);	// 禁止左值赋值构造

unique_ptr<string> p3(std::move(p1));
p1 = std::move(p2);	// 使用move把左值转成右值就可以赋值了,效果和auto_ptr赋值一样

cout << "p1 = p2 赋值后:" << endl;
cout << "p1:" << p1.get() << endl;
cout << "p2:" << p2.get() << endl;

 修饰赋值后效果与auto_ptr赋值一样

三、shared_ptr 

共享指针share_ptr是一种可以共享所有权的智能指针,它允许多个智能指针指向同一个对象,并使用引用计数的方式来管理指向对象的指针(成员函数use_count()可以获得引用计数),该对象和其相关资源会在“最后一个引用被销毁”时候释放。

shared_ptr是为了解决auto_ptr在对象所有权上的局限性(auto_ptr是独占的),使用引用计数的机制上提供了可以共享所有权的智能指针。

1、shared_ptr在内部会维护着一份引用计数,用来记录该份资源被几个对象共享。
2、当一个shared_ptr对象被销毁时(调用析构函数),析构函数内就会将该计数减1。
3、如果引用计数减为0后,则表示自己是最后一个使用该资源的shared_ptr对象,必须释放资源。
4、如果引用计数不是0,就说明自己还有其他对象在使用,则不能释放该资源,否则其他对象就成为野指针

shared_ptr的循环使用

A类中有B的智能指针;
B类中有A的智能指针;
当他们交叉互相持有对方的管理对象时程序结束了,但是并没有释放内存

 函数结束后,栈回收,首先回收pc pc被回收了cccc的引用计数器由2变成1,因为spc还在指向cccc,接着pb被回收,bbbb的引用计数器也由2变1,因为spb还在指向bbbb,函数结束,正常bbbb和cccc应该引用计数器归0被自动回收 但是spc和spb互相指向对方,导致循环使用,内存泄漏。

在使用shared_ptr智能指针时,要注意避免对象交叉使用智能指针的情况! 否则会导致内存泄露!

#include <iostream>
using namespace std;
 
class Count{
public:
	Count(){
		count = 1;
	}
	void Increase(){
		count++;
	}
	void Decrease(){
		count--;
	}
	int GetCount(){
		return count;
	}
private:
	int count = 0;  //不能直接赋值为1,防止成员声明时SmartPtr<int> sp,引用计数会错误为1
};
 
template<typename T>
class SmartPtr{
public:
	SmartPtr(): ptr_(nullptr),count_(nullptr){}
	explicit SmartPtr(T*ptr) : ptr_(ptr), count_(new Count()) {}
 
	~SmartPtr(){
		if(count_!=nullptr){
			count_->Decrease();
			if(count_->GetCount() == 0){
				delete ptr_;
				delete count_;
				ptr_ = nullptr;
				count_ = nullptr;
			}
		}
	}
	SmartPtr(const SmartPtr<T>& other){
		ptr_ = other.ptr_;
		count_ = other.count_;
		count_->Increase();
	}
 
	SmartPtr<T>& operator=(const SmartPtr<T>& other) {
		if(ptr_ == other.ptr_) {
			return *this;
		}
		ptr_ = other.ptr_;
		count_ = other.count_;
		count_->Increase();
		return *this;
	}
 
	T* get() {
		return ptr_;
	}
 
	T* operator->() {
		return ptr_;
	}
 
	T& operator*() {
		return *ptr_;
	}
 
	int GetCnt(){
		if (count_ == nullptr) return 0;
		return count_->GetCount();
	}
 
private:
	Count* count_;
	T* ptr_;
};
 
class Test {
	int a{23};
	string b{"asdad"};
};
 
int main(){
	SmartPtr<Test> sp0;
	cout<<"sp0: "<<sp0.GetCnt() <<endl;
	{
		SmartPtr<Test> sp1(new Test());
		cout<<"sp1: "<<sp1.GetCnt() <<endl;
		SmartPtr<Test> sp2(sp1);
		cout<<"sp2: "<<sp2.GetCnt() <<endl;
		sp0 = sp2;
		cout<<"sp0: "<<sp0.GetCnt() <<endl;
	}
	cout<<"sp0: "<<sp0.GetCnt() <<endl;
	return 0;
}

因此在shared_ptr底层中在对引用计数进行访问之前,首先对其加锁,当访问完毕之后,在对其进行解锁。所以shared_ptr的引用计数是线程安全的。

多个线程访问sharedptr指向的资源时,引用计数时线程安全的 但是要对管理对象进行修改就需要上锁。

四、weak_ptr 

weak_ptr类的对象它可以指向shared_ptr,并且不会改变shared_ptr的引用计数。一旦最后一个shared_ptr被销毁时,对象就会被释放。

它的提出主要是解决shared_ptr存在循环引用的问题

weak_ptr不能单独使用,应该通过shared_ptr构造而来

weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。

【博客17】利用weak_ptr解决 “循环引用“_weakptr如何解引用循环-CSDN博客

weak_ptr wpGirl_1; // 定义空的弱指针
weak_ptr wpGirl_2(spGirl); // 使用共享指针构造
wpGirl_1 = spGirl; // 允许共享指针赋值给弱指针

智能指针常用函数:

get() 获取智能指针托管的指针地址

release() 取消智能指针对动态内存的托管

reset() 重置智能指针托管的内存地址,如果地址不一致,原来的会被析构掉

  • 19
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值