1、智能指针的概念
(1)指针及其存在的问题
指针是一个变量,它的值为另一个变量的地址。使用指针可以很灵活地操纵数据对象,但是指针使用不当会造成内存泄漏、指向的内存出错、野指针等问题使程序崩溃。
(2)智能指针的引入
我们先看下面这段代码:
void RemoveAt(vector<char*> &v, int i)
{
if(i < v.size())
v.erase(v.begin() + i);
}
在执行vector删除元素时,并没有释放指针所指向的空间,就引起了内存泄漏,这是大家常犯的错误。而如何避免这个问题?我们可能会说,我在删除元素前delete掉当前指针不就行了?是的,你现在这么想,其他人可不会时常记得,如果你要对一个庞大的工程进行检查,看是否有这种潜在的内存泄露问题,那会是一场灾难!
我们知道,面向对象编程中,一个类包含了构造函数和析构函数,在构造函数中,我们可以对类中成员变量进行内存分配,而在析构函数中,我们可以对类中成员变量进行内存回收。
C++正是将类的析构思想应用到了指针中,因此,C++引入了智能指针的概念,智能指针是一个类类型对象,在其内部封装了一个普通指针。当智能指针对象因离开作用域而被析构时,其析构函数被执行,通过其内部封装的普通指针,销毁该指针的目标对象,避免内存泄露。
2、智能指针的使用
- STL一共给我们提供了四种智能指针:auto_ptr、unique_ptr、shared_ptr和weak_ptr。
- 所在头文件:#include<memory>
- 用法举例:
#include <memory> #include <iostream> using namespace std; class A { public: void fun() { cout << "A::fun()" << endl; } ~A() { cout << "~A has been called" << endl; } }; int main() { { std::auto_ptr<A> sp(new A); //创建智能指针 sp->fun(); //引用智能指针的内容 sp.reset(new A); //给智能指针重新赋值,原来的指针将被析构 A a = *sp; //获取智能指针指向的内容 }//离开作用域后,智能指针析构 { std::unique_ptr<A> sp(new A); sp->fun(); } { std::shared_ptr<A> sp(new A); sp->fun(); } { std::shared_ptr<A> sp1(new A); std::shared_ptr<A> sp2 = sp1; std::weak_ptr<A> wp(sp2); //观测sp2所指向内容 cout << wp.expired() << endl; //观测智能指针是否已经失效 False cout << wp.use_count() << endl; //观测智能指针的引用计数 2 } system("pause"); return 0; }
3、auto_ptr、unique_ptr、shared_ptr、weak_ptr的用法与区别
当两个智能指针指向同一个对象时,如以下代码块,在其结束后,程序将试图删除同一个对象两次(一次是sp1过期时,另一次是sp2过期时)。这就出现了问题,为了避免这种问题,auto_ptr、unique_ptr、shared_ptr分别采取了不同的方式:
{
std::auto_ptr<A> sp1(new A);
std::auto_ptr<A> sp2 = sp1;
}
(1)auto_ptr和unique_ptr
对于特定的对象,只能有一个智能指针可拥有,这样只有拥有对象的智能指针的构造函数会删除该对象。然后让赋值操作转让所有权。
auto_ptr和unique_ptr的区别是,在执行sp2 = sp1这条语句时,auto_ptr方式将会让sp2剥夺sp1的所有权,并且在以后的代码中继续访问sp1将会出错,因此auto_ptr是不安全的,这也是它被摒弃的原因。而unique_ptr会在编译的时候提示这条语句非法,所以unique_ptr更安全,并且,当程序试图将一个 unique_ptr 赋值给另一个时,如果源 unique_ptr 是个临时右值,编译器允许这么做;如果源 unique_ptr 将存在一段时间,编译器将禁止这么做。
(2)shared_ptr
对于特定的对象,可以由多个智能指针拥有,但需要创建智能更高的指针,跟踪引用特定对象的智能指针数。这称为引用计数。例如,赋值时,计数将加1,而指针过期时,计数将减1,当减为0时才调用delete。
(3)weak_ptr
weak_ptr是为了配合shared_ptr而引入的一种智能指针,因为它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。weak_ptr可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。使用weak_ptr的成员函数use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count()==0,但更快,表示被观测的资源(也就是shared_ptr的管理的资源)已经不复存在。weak_ptr可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象, 从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr。
比较详细的文章参考:https://www.cnblogs.com/lanxuezaipiao/p/4132096.html