智能指针作用:
一般的指针,存在资源泄露的问题。而智能指针一定会保证资源自动释放(会自动调用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();
}