一起聊聊C++中的智能指针

目录
  • 一:背景
  • 二:关键词解析
    • 1. auto_ptr
    • 2. auto_ptr 多引用问题

一:背景

我们知道 C++ 是手工管理内存的分配和释放,对应的操作符就是 new/delete 和 new[] / delete[], 这给了程序员极大的自由度也给了我们极高的门槛,弄不好就得内存泄露,比如下面的代码:

void test() {
	int* i = new int(10);
	*i = 10;
}

int main() {
	test();
}

这段代码因为用了 new 而忘了 delete,导致在 nt heap 上分配的 i 随着栈地址的回收而成了一块孤悬海外的内存占用,所以修正后的代码如下:

void test() {
	int* i = new int(10);
	*i = 10;

	delete i;
}

int main() {
	test();
}

但这种写法比较麻烦,智者千虑必有一失,总会有忘记加 delete 的时候,那怎么办呢? 大家应该知道内存自动管理有两种手段。

1.引用计数

代表作有 Python,PHP,还有 windows 的句柄管理。

2.引用跟踪

代表作有 C#,JAVA 等一众工程化语言。

因为 引用计数 实现比较简单,主要就是记录下对象的引用次数,次数为 0 则释放,所以可完全借助 类的构造函数析构函数 和 栈的自动回收特性 弄一个简单的 引用计数 ,对应着如下四个关键词。

  • auto_ptr
  • shared_ptr
  • unique_ptr
  • weak_ptr

接下来我们逐个聊一聊。

二:关键词解析

1. auto_ptr

这是 C++ 最早出现一个的 简单引用计数法,参考代码如下:

void test() {
	auto_ptr<int> ptr = auto_ptr<int>(new int(10));
}

int main() {
	test();
}

接下来看下汇编代码:

auto_ptr<int> ptr = auto_ptr<int>(new int(10));
...
00771D26  call        std::auto_ptr<int>::auto_ptr<int> (07710FAh)  
00771D2B  lea         ecx,[ebp-0D8h]  
00771D31  call        std::auto_ptr<int>::~auto_ptr<int> (0771159h)

可以看到,它分别调用了 构造函数 和 析构函数,接下来找下 auto_ptr 这两个函数的源码。

class auto_ptr {

private:
	_Ty* _Myptr; // the wrapped object pointer

public:
	auto_ptr(auto_ptr_ref<_Ty> _Right) noexcept {
		_Ty* _Ptr = _Right._Ref;
		_Right._Ref = nullptr; // release old
		_Myptr = _Ptr; // reset this
	}

	~auto_ptr() noexcept {
		delete _Myptr;
	}
}

源码一看就明白了,在构造函数中,将 new int 的地址塞给了内部的 _Myptr 指针,在析构函数中对 _Myptr 进行 delete ,真好,这样就不用整天担心有没有加 delete 啦。

值得注意的是,现在 C++ 不推荐这个了,而是建议使用新增的:shared_ptr,unique_ptr,weak_ptr, 怎么说呢? auto_ptr 有一个不好处理的问题,就是现实开发中会出现这么个场景,多个 ptr 指向同一个 引用,如下图:

2. auto_ptr 多引用问题

方式1:

定义三个 ptr,然后包装同一个 new int 地址,参考代码如下:

void test() {
	int* i = new int(10);

	auto_ptr<int> ptr1(i);
	auto_ptr<int> ptr2(i);
	auto_ptr<int> ptr3(i);
}

这种写法有没有问题呢? 肯定有问题啦,还记得 auto_ptr 的析构是 delete 吗? 对同一块内存多次 delete 会抛异常的,如下图所示:

方式2:

既然定义三个有问题, 那就用赋值运算符= 让 ptr1,ptr2,ptr3 指向同一个地址是不是就可以啦? 参考代码如下:

void test() {
	int* i = new int(10);

	auto_ptr<int> ptr1(i);
	auto_ptr<int> ptr2 = ptr1;
	auto_ptr<int> ptr3 = ptr2;
}

int main() {
	test();
}

那这段代码有没有问题呢? 有没有问题得要看 = 运算符是如何重写的,扒一下源码看看。

template <class _Other>
auto_ptr& operator=(auto_ptr<_Other>& _Right) noexcept {
	reset(_Right.release());
	return *this;
}
_Ty* release() noexcept {
	_Ty* _Tmp = _Myptr;
	_Myptr = nullptr;
	return _Tmp;
}

从源码看有一个很恶心的点,他会将 _Right 下的 _Myptr 设为 nullptr,也就是说此时的 ptr1 报废了,言外之意就是后续再访问 ptr1 会抛 访问违例。

哈哈,C++里面的专业术语叫 控制权转移。

以上就是一起聊聊C++中的智能指针的详细内容,更多关于C++智能指针的资料请关注我们其它相关文章!

(0)

相关推荐

  • C++超详细讲解智能指针

    目录 一.内存泄漏-永恒的话题 二.深度思考 三.智能指针分析 四.小结 一.内存泄漏-永恒的话题 动态申请堆空间,用完后不归还 C++ 语言中没有垃圾回收的机制 指针无法控制所指堆空间的生命周期 下面看一段内存泄漏的代码: #include <iostream> #include <string> using namespace std; class Test { int i; public: Test(int i) { this->i = i; } int value()

  • C++的智能指针你真的了解吗

    目录 什么是RAII RAII的原理 裸指针存在的问题 auto_ptr unique_ptr 总结 什么是RAII RAII(Resource Acquisition Is Initialization)是由C++之父提出的,中文翻译为资源获取即初始化,使用局部对象来管理资源的技术称为资源获取即初始化:这里的资源主要是指操作系统中有限的东西如内存(heap).网络套接字.互斥量.文件句柄等等,局部对象是指存储在栈的对象,它的生命周期是由操作系统来管理的,无需人工介入 RAII的原理 资源的使用

  • C++智能指针详解

    目录 一. unique_ptr独占指针 特点 创建方式 传递方式 简单使用 隐藏危险 二. shared_ptr 计数指针 特点 传递方式 隐藏危险 三. weak_ptr 优缺点: 智能指针由原始指针的封装,优点是可以自动分配内存,不用担心内存泄漏问题. 用于解决独占/共享所有权指针的释放,传输等问题. 但是没有原始指针方便. 一. unique_ptr独占指针 特点 都是围绕独占展开 特点一: 如其名,独占.也就是说同一个内存空间同时只能有一个指针来管理. int* pi = new in

  • C++智能指针之shared_ptr的具体使用

    目录 std::shared_ptr概念 shared_ptr模板类 shared_ptr的构造和析构 shared_ptr赋值 make_shared 计数线程安全? enable_shared_from_this shared_ptr使用注意事项: 总结 std::shared_ptr概念 unique_ptr因为其局限性(独享所有权),一般很少用于多线程操作.在多线程操作的时候,既可以共享资源,又可以自动释放资源,这就引入了shared_ptr. shared_ptr为了支持跨线程访问,其

  • C++深入分析讲解智能指针

    目录 1.简介 2.unique_ptr指针(独占指针) 3.shared_ptr指针(共享所有权) 4.weak_ptr(辅助作用) 5.自实现初级版智能指针 6.总结 1.简介 程序运行时存在静态空间.栈和堆区,用堆来存储动态分配空间的对象即那些在程序运行时分配空间的对象,若该对象不再使用,我们必须显式的销毁它们,避免内存泄漏. 智能指针是一个可以像指针一样工作的对象,有unique_ptr(独占指针),shared_ptr与weak_ptr等智能指针,定义在<memory>头文件中,可以

  • C++智能指针shared_ptr

    目录 1.什么是shared_ptr? 2.shared_ptr支持哪些操作? 3.如何创建shared_ptr的实例? 4.什么是shared_ptr的引用计数?如何查看? 5.shared_ptr何时释放其所指向的对象? 1.什么是shared_ptr? C++11中包括shared_ptr在内的多种指针,都是模板类型,意味着使用者可以指定想要操作的类型. 创建shared_ptr的方式如下: shared_ptr<int>p1; // p1=NULL 2.shared_ptr支持哪些操作

  • c++智能指针的超详细讲解

    目录 1.什么是智能指针 2.原始指针的问题 3.unique_ptr 4.shared_ptr 5.shared_ptr使用需要注意的点 5.1 不能将一个原始指针初始化多个shared_ptr 5.2.循环引用问题 6.智能指针小结 总结 1.什么是智能指针 从比较简单的层面来看,智能指针是RAII(Resource Acquisition Is Initialization,资源获取即初始化)机制对普通指针进行的一层封装.这样使得智能指针的行为动作像一个指针,本质上却是一个对象,这样可以方

  • 关于C++智能指针shared_ptr和unique_ptr能否互转问题

    C++中的智能指针最常用的是shared_ptr和unique_ptr,C++新手最常问的问题是我从一个函数中拿到unique_ptr,但要转成shared_ptr才能使用,要怎么转换?同理是否能将shared_ptr转换成unique_ptr? 我们先简单看看shared_ptr是什么. std::shared_ptr<Widget> a = std::make_shared<Widget>(); 这句代码会在栈中创建一个shared_ptr对象,其最基本的2个指针,一个指向在堆

  • C++智能指针之shared_ptr详解

    目录 共享指针的初始化方式 常用成员函数 shared_ptr内存模型 make_shared的优缺点 优点 缺点 引用计数 比较运算符 总结 共享指针的初始化方式 1.裸指针直接初始化,但不能通过隐式转换来构造 2.允许移动构造,也允许拷贝构造 3.通过make_shared构造 例: #include <iostream> #include <memory> class Frame {}; int main() { std::shared_ptr<Frame> f(

  • 一起聊聊C++中的智能指针

    目录 一:背景 二:关键词解析 1. auto_ptr 2. auto_ptr 多引用问题 一:背景 我们知道 C++ 是手工管理内存的分配和释放,对应的操作符就是 new/delete 和 new[] / delete[], 这给了程序员极大的自由度也给了我们极高的门槛,弄不好就得内存泄露,比如下面的代码: void test() { int* i = new int(10); *i = 10; } int main() { test(); } 这段代码因为用了 new 而忘了 delete,

  • C++中auto_ptr智能指针的用法详解

    智能指针(auto_ptr) 这个名字听起来很酷是不是?其实auto_ptr 只是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势,但也有其局限.本文总结的8个问题足以涵盖auto_ptr的大部分内容. auto_ptr是什么? auto_ptr 是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个拥有者.当auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥有

  • C++11中的智能指针shared_ptr、weak_ptr源码解析

    目录 1.前言 2.源码准备 3.智能指针概念 4.源码解析 4.1.shared_ptr解析 4.1.1.shared_ptr 4.1.2.__shared_ptr 4.1.3.__shared_count 4.1.4._Sp_counted_base 4.1.5._Sp_counted_ptr 4.1.6.shared_ptr总结 4.2.weak_ptr解析 4.2.1.weak_ptr 4.2.2.__weak_ptr 4.2.3.__weak_count 4.2.4.回过头看weak_

  • C++ 中boost::share_ptr智能指针的使用方法

    C++ 中boost::share_ptr智能指针的使用方法 最近项目中使用boost库的智能指针,感觉智能指针还是蛮强大的,在此贴出自己学习过程中编写的测试代码,以供其他想了解boost智能指针的朋友参考,有讲得不正确之处欢迎指出讨论.当然,使用boost智能指针首先要编译boost库,具体方法可以网上查询,在此不再赘述. 智能指针能够使C++的开发简单化,主要是它能够自动管理内存的释放,而且能够做更多的事情,即使用智能指针,则可以再代码中new了之后不用delete,智能指针自己会帮助你管理

  • C++中的auto_ptr智能指针的作用及使用方法详解

    智能指针(auto_ptr) 这个名字听起来很酷是不是?其实auto_ptr 只是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势,但也有其局限.本文总结的8个问题足以涵盖auto_ptr的大部分内容.  auto_ptr是什么? auto_ptr 是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个拥有者.当auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥

  • C++智能指针读书笔记

    最近在补看<C++ Primer Plus>第六版,这的确是本好书,其中关于智能指针的章节解析的非常清晰,一解我以前的多处困惑.C++面试过程中,很多面试官都喜欢问智能指针相关的问题,比如你知道哪些智能指针?shared_ptr的设计原理是什么?如果让你自己设计一个智能指针,你如何完成?等等--.而且在看开源的C++项目时,也能随处看到智能指针的影子.这说明智能指针不仅是面试官爱问的题材,更是非常有实用价值. C++通过一对运算符 new 和 delete 进行动态内存管理,new在动态内存中

  • C++11 智能指针之shared_ptr代码详解

    C++中的智能指针首先出现在"准"标准库boost中. 随着使用的人越来越多,为了让开发人员更方便.更安全的使用动态内存,C++11也引入了智能指针来管理动态对象. 在新标准中,主要提供了shared_ptr.unique_ptr.weak_ptr三种不同类型的智能指针. 接下来的几篇文章,我们就来总结一下这些智能指针的使用. 今天,我们先来看看shared_ptr智能指针. shared_ptr 智能指针 shared_ptr是一个引用计数智能指针,用于共享对象的所有权也就是说它允许

  • c++11 新特性——智能指针使用详解

    c++11添加了新的智能指针,unique_ptr.shared_ptr和weak_ptr,同时也将auto_ptr置为废弃(deprecated). 但是在实际的使用过程中,很多人都会有这样的问题: 不知道三种智能指针的具体使用场景 无脑只使用shared_ptr 认为应该禁用raw pointer(裸指针,即Widget*这种形式),全部使用智能指针 初始化方法 class A { public: A(int size){ this->size = size; } A(){} void Sh

  • c++ 智能指针基础详解

    简介 在现代 C++ 编程中,标准库包含了智能指针(Smart pointers). 智能指针用来确保程序不会出现内存和资源的泄漏,并且是"异常安全"(exception-safe)的. 智能指针的使用 智能指针定义在头文件 memory 里的命名空间 std 中.它对于资源获取即初始化(RAII, Resource Acquisition Is Initialization) 编程理念至关重要.该理念的目的是保证对象初始化的时候也是资源获取的时候,从而使对象的所有资源在单行代码中创建

  • C++ 智能指针的魅力你都了解吗

    前情提要 我们知道除了静态内存和栈内存外,每个程序还有一个内存池,这部分内存被称为自由空间或者堆.程序用堆来存储动态分配的对象即那些在程序运行时分配的对象,当动态对象不再使用时,我们的代码必须显式的销毁它们. 在C++中,动态内存的管理是用一对运算符完成的:new和delete,ne:在动态内存中为对象分配一块空间并返回一个指向该对象的指针,delete指向一个动态独享的指针,销毁对象,并释放与之关联的内存. 动态内存管理经常会出现两种问题:一种是忘记释放内存,会造成内存泄漏:一种是尚有指针引用

随机推荐