C++:10.智能指针

智能指针作用:

一般的指针,存在资源泄露的问题。而智能指针一定会保证资源自动释放(会自动调用delete),不用用户参与。

为什么会自动调用delete?

实际上智能指针也是用类定义的,利用栈上的指针出函数就会自动调用析构函数的特点。

所以不能使用堆上的指针,因为出函数不会析构。也不要定义全局的,因为程序结束自己就释放了。

头文件:#include <memory>


1、带引用计数的智能指针。

1)shared_ptr   强智能指针  可以改变资源的引用计数。 会出现循环引用的问题。

如果多个shared_ptr指向了同一块资源。该资源的引用计数就每次加1。如果不指向了就减1。当引用计数为0时,就会自动释放该资源。

shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁。

初始化方式:智能指针是个类,并不是一个指针(虽然它的成员变量是个指针)。所以不能将一个指针直接赋值给智能指针。也就是说:shared_ptr<int> pra = new int; 这种写法是错的。而是应该shared_ptr<int> pra(new int);

2)weak_ptr      弱智能指针  不会改变资源的引用计数。

弱智能指针不能直接访问对象,但如果提升为强智能指针(引用计数+1)就可以访问,用lock()方法。前提资源还存在,引用计数不为0。如果资源没了,当然指向NULL。出局部析构-1;

多线程也是安全的,不会出现刚提升,就有其他线程析构了。因为+1了,+1是上了锁的。

弱智能指针可以直接接受强智能指针.

弱智针是不可以使用->来访问对象的。需要将弱智针提升为强指针。shared_ptr<A> ptra = _ptra.lock();  // 提升

shared_ptr和weak_ptr的使用建议:

结论:创建对象的地方使用强智能指针,其它地方一律使用弱智能指针。

2、不带引用计数的智能指针。

1、auto_ptr

在C++标准提供了auto_ptr。这个智能指针不支持拷贝构造函数。当想ptr2(ptr1); 会将ptr1置为NULL,ptr2指向ptr1之前的地址。所以禁止使用C++标准可提供的auto_ptr

可以任意转移资源的所有权,但用户无法感知。

2、scope_ptr

 禁止拷贝构造与赋值。方式是私有的。不能任意转化所有权。

3、unique_ptr

同一时刻只能有一个unique_ptr指向给定的对象。不能赋值,不能拷贝。但用户可以调用函数(move)还转换所有权。

遗留问题:1、拷贝构造和赋值不能在同一个作用域下使用,但可以在一个函数返回时调用。
                             2、不是所有资源都是使用delete 那么怎么定义删除器。

unique_ptr<int> getUniquePtr_1()
{
	unique_ptr<int> p(new int);
	return p;   返回局部变量,C++优化规则.
}
unique_ptr<int> getUniquePtr_2()
{
    return unique_ptr<int> (new int);返回临时量
}

int main()
{

	unique_ptr<int> p1(new int);
	unique_ptr<int> p2(p1);   拷贝构造报错
	p2 = p1;                  赋值重载报错

	unique_ptr<int> p3 = getUniquePtr_1();正确,直接拷贝构造p3.
}

在unique_ptr中拷贝构造与赋值重载是放在public中的,通过在后面加=delete。从而达到删除该函数的目的,导致无法使用。
但其实还提供了右值引用(C++11)的拷贝构造与赋值重载。在这里调用的就是右值引用的函数。

智能指针的循环引用(交叉引用)问题:

解决方法:创建对象的地方使用强智能指针,其它地方一律使用弱智能指针。也就是说在类中的指针使用弱指针即可。

原因:弱指针引用计数不会加一。


一个将弱智针提升为强指针的例子:

class B;
class A
{
public:
	A(){ cout << "A()" << endl; }
	~A(){ cout << "~A()" << endl; }
	void func(){ cout << "call A::func" << endl; }
	weak_ptr<B> _ptrb;
};
class B
{
public:
	B(){ cout << "B()" << endl; }
	~B(){ cout << "~B()" << endl; }
	void test()
	{
		// 想通过_ptra访问A对象的func方法,调用一下
		shared_ptr<A> ptra = _ptra.lock();  // 提升
		if (ptra != NULL) // 提升成功,调用func方法
		{
			ptra->func();
		}
	}
	weak_ptr<A> _ptra; // operator-> 不允许通过weak_ptr访问对象
};

int main()
{
	shared_ptr<A> ptra(new A());
	shared_ptr<B> ptrb(new B());
	ptra->_ptrb = ptrb;
	ptrb->_ptra = ptra;

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