C++ 智能指针

一.简介

C++的入门坑点大家都是有目共睹的,无非就是指针的理解不深导致一些野指针,内存泄露等问题,所以就不赘述。智能指针正好能够弥补这些问题,因为它本质是存放在栈的模板对象,只是在栈内部包了一层指针。而栈在其生命周期结束时,其中的指针指向的堆内存也自然被释放了。因而实现了智能管理的效果,不需要考虑内存问题了,其实有点类似某种单例写法,程序运行结束,也不用考虑单例对象内存问题。

c++11之前的auto_ptr; c++11新加的unique_ptr, shared_ptr以及weak_ptr。

包含头文件 #include <memory>

在C++11中,引入了智能指针。主要有:unique_ptr, shared_ptr, weak_ptr。
这3种指针组件就是采用了boost里的智能指针方案。很多有用过boost智能指针的朋友,很容易地就能发现它们之间的关间。

std boost 功能说明
unique_ptr scoped_ptr 独占指针对象,并保证指针所指对象生命周期与其一致
shared_ptr shared_ptr 可共享指针对象,可以赋值给shared_ptr或weak_ptr。
指针所指对象在所有的相关联的shared_ptr生命周期结束时结束,是强引用。
weak_ptr weak_ptr 它不能决定所指对象的生命周期,引用所指对象时,需要lock()成shared_ptr才能使用。

 二.auto_ptr

auto_ptr是标准库里的智能指针,存在许多缺陷。 

//常用一些方法

1.get():返回当前指针对象

2.release():清空当前智能指针对象,并返回类型指针。所以假如我们要正常删除,那么需要这样:

Base1*base2 = base1.release();
delete base2;

 3.reset():重置智能指针,即把内存删除,且智能指针指向空,但类型不变,所以可以这样安全便捷地删除:

base1.reset();

4.auto_ptr还重载了等号操作符

auto_ptr <Base1> base2;

//将base1的控制权转交给base2,且base1清空了
base2 = base1;

因此这样就有些问题,控制权可以随便转换,但是只有一个在用,用起来会受到诸多限制。

三.unique_ptr

unique_ptr 由 C++11 引入,旨在替代不安全的 auto_ptr,它持有对对象的独有权——两个unique_ptr不能指向一个对象,即 unique_ptr 不共享它所管理的对象。unique_ptr不支持普通的拷贝或赋值操作。只能移动 unique_ptr,即对资源管理权限可以实现转移。

虽然我们不能拷贝或者赋值unique_ptr,但是可以通过调用release或reset将指针所有权从一个(非const)unique_ptr转移给另一个unique_ptr。

move函数可以是用于构造函数,也可以用于赋值函数,但需要手动显示添加,move函数用直白点的话来说就是省去拷贝构造和赋值时中间的临时对象,将资源的内存从一个对象移动到(共享也可以)另一个对象。

//将所有权从p1转移给p2,将p1置为空
unique_ptr<string> p2(p1.release());

//将所有权从p3转移到p2,reset释放了p2原来指向的内存
unique_ptr<string>p3(new string("Trex"));
p2.reset(p3.release());

//base1变成empty
unique_ptr<Base1>	base1(new Base1);
unique_ptr<Base1>	base2 = move(base1);

//base2变成empty
unique_ptr<Base1>	base3;
base3 = move(base2);

 四.shared_ptr

 shared_ptr 是一个标准的共享所有权的智能指针,允许多个指针指向同一个对象;可以直接赋值和调用拷贝构造函数,且不会清空原本的智能指针。

 

 

//最安全的分配和使用动态内存的方法就是调用一个名为make_shared的标准库函数,此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。
shared_ptr<int> p3 = make_shared<int>(42);
shared_ptr<string> p4 = make_shared<string>(10,'9');
shared_ptr<int> p5 = make_shared<int>();

shared_ptr<Base1>	base1(new Base1);
shared_ptr<Base1>	base2 = base1;
shared_ptr<Base1>	base3;
base3 = base2;//三个共享一个

当删除一个智能指针时,并不影响其它两个智能指针的继续使用。因为该片内存添加了一个引用计数,每shared_ptr一次,引用计数+1;每次调用析构函数,引用计数减一。直到最后一个智能指针删除,才会释放内存。 

shared_ptr和unique_ptr一样可以通过move来切换控制权,这个时候是切换,不是共享了。auto_ptr和unique_ptr都可以通过move函数转换成shared_ptr类型,当然,一样是切换控制权的形式,即旧的置空。

auto_ptr<Base1>	     base1(new Base1);
shared_ptr<Base1>	 base2=move(base1);

五.weak_ptr

weak_ptr 被设计为与 shared_ptr 共同工作,可以从一个 shared_ptr 或者另一个 weak_ptr 对象构造而来。weak_ptr 是为了配合 shared_ptr 而引入的一种智能指针,它更像是 shared_ptr 的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载 operator* 和 operator-> ,因此取名为 weak,表明其是功能较弱的智能指针。它的最大作用在于协助 shared_ptr 工作,可获得资源的观测权,像旁观者那样观测资源的使用情况。观察者意味着 weak_ptr 只对 shared_ptr 进行引用,而不改变其引用计数,当被观察的 shared_ptr 失效后,相应的 weak_ptr 也相应失效。
 

 

#include < assert.h>

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

int main()
{
	shared_ptr<int> sp(new int(10));
	assert(sp.use_count() == 1);

    //从shared_ptr创建weak_ptr
	weak_ptr<int> wp(sp); 	
	assert(wp.use_count() == 1);

    //判断weak_ptr观察的对象是否失效
	if (!wp.expired())		
	{
		shared_ptr<int> sp2 = wp.lock();//获得一个shared_ptr
		*sp2 = 100;
		assert(wp.use_count() == 2);
	}
	assert(wp.use_count() == 1);
	cout << "int:" << *sp << endl;
    return 0;
}

从上面可以看到,尽管以 shared_ptr 来构造 weak_ptr,但是 weak_ptr内部的引用计数并没有什么变化

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章