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

目录
  • 什么是RAII
    • RAII的原理
  • 裸指针存在的问题
  • auto_ptr
  • unique_ptr
  • 总结

什么是RAII

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

RAII的原理

资源的使用一般经历三个步骤:

  • 获取资源(创建对象)
  • 使用资源
  • 销毁资源(析构对象)

但是资源的销毁往往是程序员经常忘记的一个环节,所以程序界就想如何在程序中让资源自动销毁呢?解决问题的方案就是:RAII,它充分的利用了C++语言局部对象自动销毁的特性来控制资源的生命周期

裸指针存在的问题

1.难以区分指向的是单个对象还是一个数组

2.使用完指针之后无法判断是否应该销毁指针,因为无法判断指针是否”拥有“指向的对象

3.在已经确定需要销毁指针的情况下,也无法确定是用delete关键字删除,还是有其他特殊的销毁机制,例如通过将指针传入某个特定的销毁函数来摧毁指针

4.即使已经确定了销毁指针的方法,由于1的原因,仍然无法确定到底是i用delete(销毁单个对象)还是delete[](销毁一个数组)

5.假设上述的问题都解决了,也很难保证在代码的所有路径中(分支结构,异常导致的挑战),有且仅有一次销毁指针的操作;任何一条路径遗漏都可能导致内存的泄露,而销毁多次则会导致未定义行为

6.理论上没有方法来分辨一个指针是否处于悬挂状态

auto_ptr

class Object
{
	int value;
public:
	Object(int x = 0) :value(x)
	{
		cout << "Create Object:" << this << endl;
	}
	~Object()
	{
		cout << "Destory Object:" << this << endl;
	}
	int& Value()
	{
		return value;
	}
};

template<class _Ty>
class my_auto_ptr
{
private:
	bool _Owns;
	_Ty* _Ptr;
public:
	my_auto_ptr(_Ty* p = NULL) :_Owns(p != NULL), _Ptr(p)
	{}
	~my_auto_ptr()
	{
		if (_Owns)
		{
			delete _Ptr;
		}
		_Owns = false;
		_Ptr = NULL;
	}
};

void fun()
{
	my_auto_ptr<Object> obj(new Object(10));
}

int main()
{
	fun();
}


在这里将Object构建完成后,将其指针给到p,当函数结束去调动智能指针的析构函数去释放空间

若我们需要在fun()函数中,去调用Object类的方法obj->Value();

class Object
{
	int value;
public:
	Object(int x = 0) :value(x)
	{
		cout << "Create Object:" << this << endl;
	}
	~Object()
	{
		cout << "Destory Object:" << this << endl;
	}
	int& Value()
	{
		return value;
	}
};

template<class _Ty>
class my_auto_ptr
{
private:
	bool _Owns;
	_Ty* _Ptr;
public:
	my_auto_ptr(_Ty* p = NULL) :_Owns(p != NULL), _Ptr(p)
	{}
	~my_auto_ptr()
	{
		if (_Owns)
		{
			delete _Ptr;
		}
		_Owns = false;
		_Ptr = NULL;
	}
	_Ty* get()const
	{
		return _Ptr;
	}
	_Ty& operator*()const
	{
		return *(get());
	}
	_Ty* operator ->()const
	{
		return get();
	}
};

void fun()
{
	my_auto_ptr<Object> obj(new Object(10));
	cout << obj->Value() << endl;
	cout << (*obj).Value() << endl;
}

int main()
{
	fun();
}

通过运算符重载,(*obj) 后将直接指向堆区(heap)的对象实体

若我们通过一个my_auto_ptr去创建另一个my_auto_ptr

class Object
{
	int value;
public:
	Object(int x = 0) :value(x)
	{
		cout << "Create Object:" << this << endl;
	}
	~Object()
	{
		cout << "Destory Object:" << this << endl;
	}
	int& Value()
	{
		return value;
	}
};

template<class _Ty>
class my_auto_ptr
{
private:
	bool _Owns;
	_Ty* _Ptr;
public:
	my_auto_ptr(_Ty* p = NULL) :_Owns(p != NULL), _Ptr(p)
	{}
	~my_auto_ptr()
	{
		if (_Owns)
		{
			delete _Ptr;
		}
		_Owns = false;
		_Ptr = NULL;
	}
	my_auto_ptr(const my_auto_ptr& obj):_Owns(obj._Owns),_Ptr(obj._ptr)
	{
	}
	my_auto_ptr& operator=(const my_auto_ptr& _Y)
	{
		if(this == &_Y) return *this;
		if(_Owns)
		{
			delete _Ptr;
		}
		_Owns = _Y._Owns;
		_Ptr = _Y._Ptr;
		return 0;
	}

	_Ty* get()const
	{
		return _Ptr;
	}
	_Ty& operator*()const
	{
		return *(get());
	}
	_Ty* operator ->()const
	{
		return get();
	}
	void reset(_Ty* p = NULL)
	{
		if (_Owns)
		{
			delete _Ptr;
		}
		_Ptr = p;
	}
	_Ty* release()const
	{
		_Ty* tmp = NULL;
		if (_Owns)
		{
			((my_auto_ptr*)this)->_Owns = false; //常性进行修改
			tmp = _Ptr;
			((my_auto_ptr*)this)->_Ptr = NULL;
		}
		return tmp;
	}
};

void fun()
{
	my_auto_ptr<Object> pobja(new Object(10));
	my_auto_ptr<Object> pobjb(pobja);
}

int main()
{
	fun();
}

如果通过浅拷贝,则两个指针拥有同一个资源,在析构的过程会造成资源的重复释放导致崩溃

若设置为将其资源进行转移

my_auto_ptr(const my_auto_ptr& obj):_Owns(obj._Owns),_Ptr(release())
{
}
my_auto_ptr& operator=(const my_auto_ptr& _Y)
{
	if(this == &_Y) return *this;
	if(_Owns)
	{
		delete _Ptr;
	}
	_Owns = _Y._Owns;
	_Ptr = _Y.release();
	return 0;
}
void fun(my_auto_ptr<Object> apx)
{
	int x = apx->Value();
	cout<<x<<endl;
}
int main()
{
	my_auto_ptr<Object> pobja(new Object(10));
	fun(pobja);
	int a = pobja->Value();
	cout<<a<<endl;
}

那么上面的过程中,资源会进行转移pobja将不再拥有资源,导致pobja失去资源进而程序崩溃

这也就是auto_ptr的局限性,也导致该智能指针的几乎没有使用

unique_ptr

该智能指针属于唯一性智能指针,将拷贝构造删除,也就不能将其新建另一个对象,同时也不能作为参数传入

class Object
{
	int value;
public:
	Object(int x = 0) :value(x)
	{
		cout << "Create Object:" << this << endl;
	}
	~Object()
	{
		cout << "Destory Object:" << this << endl;
	}
	int& Value()
	{
		return value;
	}
};

int main()
{
	std::unique_ptr<Object> pobja(new Object(10));
	//std::unique_ptr<Object> pobjb(pobja); error
	//不允许
	std::unique_ptr<Object> pobjb(std::move(pobja));
}

通过移动赋值是可以的,通过明确的概念,对其资源进行转移

同时unique_ptr可以区分其所指向的是一个单独空间,或者是连续的空间

struct delete_ar_object
{
	void operator()(Object* op)
	{
		if(op == NULL) return;
		delete[] op;
	}
}
int main()
{
	std::unique_ptr<Object> pobja(new Object(10));
	std::unique_ptr<Object,delete_ar_object> pobjb(new Object[10]);
}

在这里如果是连续空间,会调用删除连续空间的删除器;单独空间则使用默认删除器

unique_ptr在编写的时候,有多个模板类,分别对应单个对象的方案和一组对象的方案

并且可以通过智能指针指向fopen打开的文件对象,而文件对象是同fclose去进行关闭的

struct delete_file
{
	void operator()(FILE *fp)
	{
		if(fp == NULL) return;
		fclose(fp);
	}
}
std::unique_ptr<FILE,delete_file> pfile(fopen("zyq.txt","w"));

这里只需要将默认的删除器,更改为对文件对象的删除器

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 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++智能指针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,aoto_ptr 2,unique_ptr 3,share_ptr 4, weak_ptr 总结 前言 如果在程序中使用new从堆分配内存,等到不再需要时,应使用delete将其释放,C++引入了智能指针auto_ptr,以帮助自动完成这个过程,但是aoto_ptr也有其局限性,因此从Boost库中又引入了三种智能指针unique_ptr shared_ptr weak_ptr. 1,aoto_ptr // ConsoleApplication1.cpp : 定义控制台应用程序的

  • c++智能指针unique_ptr的使用

    目录 1.为什么需要unique_ptr 2.什么是unique_ptr 3.unique_ptr特性 4.如何使用unique_ptr 4.1简单使用 4.2指向数组 5.unique_ptr需要注意什么 1.为什么需要unique_ptr 与shared_ptr作用类似,需要解决内存泄漏的问题,但是却不需要使用shared_ptr的引用计数,所以为了减少消耗,就需要一个这样的智能指针.但是使用已被废弃的auto_ptr的话就会有新的问题,auto_ptr在使用过程中如果被拷贝构造或者赋值的话

  • C++Smart Pointer 智能指针详解

    目录 一.为啥使用智能指针呢 二.shared_ptr智能指针 三.unique_ptr智能指针 四.weak_ptr智能指针 五.智能指针怎么解决交叉引用,造成的内存泄漏 5.1交叉引用的栗子: 5.2解决方案 六.智能指针的注意事项 总结 一.为啥使用智能指针呢 标准库中的智能指针: std::auto_ptr --single ownership (C++98中出现,缺陷较多,被摒弃) std::unique_ptr --single ownership (C++11替代std::auto

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

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

  • C++智能指针实例详解

    本文通过实例详细阐述了C++关于智能指针的概念及用法,有助于读者加深对智能指针的理解.详情如下: 一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 delete 的情况并不罕见. 用智能指针便可以有效缓解这类问题,本文主要讲解参见的智能指针的用法.包括:std::auto_ptr.boost::scoped_ptr.boost::shared_p

  • 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++ 中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++智能指针介绍 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete,比如流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 delete 的情况并不罕见,并造成内存泄露.如此c++引入 智能指针 ,智能指针即是C++ RAII的一种应用,可用于动态资源管理,资源即对象的管理策略. 智能指针在 <memory>标头文件的 std 命名空间中定义. 它们对 RAII 或 获取资源即初始化 编程惯用法至关重要. RAII 的主要原则是

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

    1. 为什么需要智能指针?简单的说,智能指针是为了实现类似于Java中的垃圾回收机制.Java的垃圾回收机制使程序员从繁杂的内存管理任务中彻底的解脱出来,在申请使用一块内存区域之后,无需去关注应该何时何地释放内存,Java将会自动帮助回收.但是出于效率和其他原因(可能C++设计者不屑于这种傻瓜氏的编程方式),C++本身并没有这样的功能,其繁杂且易出错的内存管理也一直为广大程序员所诟病. 更进一步地说,智能指针的出现是为了满足管理类中指针成员的需要.包含指针成员的类需要特别注意复制控制和赋值操作,

  • 浅析Boost智能指针:scoped_ptr shared_ptr weak_ptr

    一. scoped_ptrboost::scoped_ptr和std::auto_ptr非常类似,是一个简单的智能指针,它能够保证在离开作用域后对象被自动释放.下列代码演示了该指针的基本应用: 复制代码 代码如下: #include <string>#include <iostream>#include <boost/scoped_ptr.hpp> class implementation{public:    ~implementation() { std::cout

  • C++智能指针shared_ptr分析

    C++智能指针shared_ptr分析 概要: shared_ptr是c++智能指针中适用场景多,功能实现较多的智能指针.它采取引用计数的方法来实现释放指针所指向的资源.下面是我代码实现的基本功能. 实例代码: template<class T> class sharedptr { public: sharedptr(T* ptr) :_ptr(ptr) , _refCount(new int(1)) {} sharedptr(sharedptr<T>& sp) :_ptr

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

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

随机推荐