C++11智能指针xxx_ptr

前言

一般来说,我们想要在上开辟内存空间需要使用关键字new,但由于使用new之后我们还是需要进行手动释放,我们却常常忘记delete,或者在不该delete的地方delete了,这就会导致程序出错。
因此C++11推出了智能指针,让程序管理内存,让程序对new出来的内存进行自动释放(在析构智能指针的时候同时delete对象),这样就能避免很多因为粗心产生的bug。

正文

(1) 三种智能指针

这三种智能指针都在头文件memory中:

  1. unsigned_ptr:可以有多个指针指向同一个对象,其中包含了一个计数器
  2. unique_ptr:独占指向的对象
  3. weak_ptr:指向shared_ptr所管理的对象

(2) 智能指针的设计思路

  • 智能指针是类模板,在栈上创建智能指针对象
  • 将普通指针交给智能指针对象
  • 智能指针对象过期时,调用析构函数释放普通指针的内存

(其实还有个auto_ptr,但是在C++17中移除了,这里也就不说了)

(3) unique_ptr

它的意思是独享,也就是一个unique_ptr对象只对一个资源负责,当它析构的时候,指向的对象所分配的内存也随之释放。
因此,它在定义的时候禁用了拷贝构造函数复制构造函数

unique_ptr& operator=( const unique_ptr& ) = delete;
constexpr unique_ptr( std::nullptr_t ) noexcept = delete;

但是我们需要注意:指针和智能指针是两种类型!!!因此,我们不能直接使用智能指针接收new出来的对象:

#include<iostream>
#include<memory>

int main(){
	// 正确
	std::unique_ptr<int> ptr(new int(5));

	// 正确,C++14的写法
	std::unique_ptr<int> ptr2 = std::make_ptr<int>(int(5));

	// 错误,不能直接使用智能指针接收直接new出来的对象
	std::unique_ptr<int> ptr3 = new int(10);

	// 错误,拷贝构造函数是已被删除的函数
	// 在VS中会显示该函数已被删除
	std::unique_ptr<int> temp_ptr(ptr);
}

它的底层原理其实也很简单:他的内部只有一个指针,这个指针指向的是它初始化时所指定的对象
这里写一段示例代码:

#include <iostream>
#include <ostream>
#include <memory>

class AA{
public:
    // 利用友元进行运算符重载
    friend std::ostream& operator<<(std::ostream& os, const AA& temp);

    AA(){
        this->val = 0;
        std::cout << "调用了AA的构造函数" << std::endl;
    }
    AA(const int&& value){
        std::cout << "调用了AA的初始化构造函数" << std::endl;
        this->val = std::move(value); 
    }
    ~AA(){
        std::cout << "调用了AA的析构函数" << std::endl;
    }
    int showVal() const{
        return this->val;
    }


private:
    int val;
};

// 需要注意ostream是命名空间std的成员
// 并且我上面没有手动使用std::
// 需要注意的点:被const声明的变量只能使用const声明的成员函数
std::ostream& operator<<(std::ostream& os, const AA& temp){
        os << temp.showVal();
        return os;
    }

int main(){
    AA* temp = new AA(100);
    std::cout << *temp << std::endl;
    std::unique_ptr<AA> auto_ptr(temp);
    std::cout << "main函数运行中" << std::endl;
}

通过输出语句的顺序,我们就能够理解它的原理:

调用了AA的初始化构造函数
100
main函数运行中
调用了AA的析构函数

它其实就是在智能指针进行析构的时候,其析构函数中再调用了其所指向对象的析构函,以此来释放所分配的内存
智能指针重载了输入输出运算符,因此我们可以像使用普通指针一样去使用智能指针
这里需要注意一个问题:不要用同一个指针(也叫裸指针或者原始指针)去初始化不同的unique_ptr对象。这个原因也很简单,就是重复释放内存的,跟深浅拷贝一样。

unique_ptr的几种初始化方法

这里我就直接给出代码吧:

#include <memory>
using namespace std;
int main(){
	unique_ptr<int> ptr1(new int(100)); // 分配内存并初始化

	unique_ptr<int> ptr2 = make_unique<int>(100); // C++14标准

	int temp = 100;
	unique_ptr<int> ptr3(temp); // 用已存在的地址初始化
}
获取unique_ptr的地址

在C++20之前,unique_ptr没有重载输出运算符,所以我们不能像使用普通指针那样输出智能指针所指向的地址:

#include <memory>
#include <iostream>
int main(){
	std::unique_ptr<int> ptr(new int(5));
	// 错误:unique_ptr不支持输出运算符
	std::cout << ptr;
}

想要获取其指向的地址,需要使用其成员函数get()

#include <memory>
#include <iostream>
int main(){
	std::unique_ptr<int> ptr(new int(5));
	// 错误:unique_ptr不支持输出运算符
	std::cout << ptr.get() << std::endl;
	std::cout << *ptr << std::endl;
}

由于智能指针为了模拟原始指针,而重载了"*“运算符和”->"运算符,因此我们能够像原始指针一样去使用它

unique_ptr的使用

这里需要重点强调的是unique_ptr作为参数进行函数传递的时候,我们都知道函数传参有两种方式:值传递引用传递
前面我们说到:由于unique_ptr是独享的,因此它禁用了拷贝构造函数复制构造函数,正是因此,unique_ptr在作为参数传递的时候只能使用引用传递:

#include <memory>
#include <iostream>

void func(std::unique_ptr<int> ptr){
	std::cout << ptr.get() << "中,存储的数据是:" << *ptr << std::endl;
}

int main(){
	std::unique_ptr<int> ptr = std::make_unique<int>(100);
	func(ptr);
}

上面这段函数会报错,正式因为使用的是值传递,只需要将函数传参变为传引用即可:

void func(std::unique_ptr<int>& ptr){}

(4) shared_ptr

std::shared_ptr底层和std::unique_ptr差不多,但它底层增加了一个计数器,用于计算共有多少个shared_ptr共享同一个对象

#include <memory>
#include <iostream>
int main(){
	std::shared_ptr<int> ptr = std::make_shared<int>(5);
	
	std::cout << "ptr = " << ptr.get() << std::endl;
	std::cout << "共有" << ptr.use_count() << "个shared_ptr指向" << ptr << std::endl;
	
	std::shared_ptr<int> ptr2 = ptr1;
	std::cout << "共有" << ptr.use_count() << "个shared_ptr指向" << ptr << std::endl;
}

知道了unique_ptr,shared_ptr就很好理解了。
现在我们来看看shared_ptr的常用方法:

  • get():和unique_ptr中的一样,获取指向底部管理着的对象的地址
  • use_count():获取当前shared_ptr中的计数器
  • 19
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

默示MoS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值