C++智能指针

参考:https://www.cnblogs.com/wxquare/p/4759020.html

http://c.biancheng.net/view/7898.html

什么是智能指针

智能指针是指向动态分配的内存区(堆)里的对象。

智能指针有什么用

用于生存期控制,确保正确销毁动态分配的对象。防止内存泄漏。

理解智能指针需要从下面三个层次:

  1. 从较浅的层面看,智能指针是利用了一种叫做RAII(资源获取即初始化)的技术对普通的指针进行封装,这使得智能指针实质是一个对象,行为表现的却像一个指针。
  2. 智能指针的作用是防止忘记调用delete释放内存和程序异常的进入catch块忘记释放内存。另外指针的释放时机也是非常有考究的,多次释放同一个指针会造成程序崩溃,这些都可以通过智能指针来解决。
  3. 智能指针还有一个作用是把值语义转换成引用语义。C++和Java有一处最大的区别在于语义不同,在Java里面下列代码:
    Animal a = new Animal();
    Animal b = a;
    你当然知道,这里其实只生成了一个对象,a和b仅仅是把持对象的引用而已。但在C++中不是这样,
    Animal a;
    Animal b = a;

    智能指针里面有什么,怎么设计实现的

利用自动调用的类的析构函数来释放内存。从较浅的层面看,智能指针是利用了一种叫做RAII(资源获取即初始化)的技术对普通的指针进行封装,这使得智能指针实质是一个对象,行为表现的却像一个指针。

  1. 引用计数。

各个智能指针的异同

auto_ptr

已经在C++11里弃用,C++11开始起用如下3个智能指针。

shared_ptr

引用计数,指向相同内存。每析构一次,引用减一,直到为0,删除指向的堆内存。线程安全,读取需要加锁。

注意点

  • 不能将指针直接赋值给一个智能指针。

  • 避免循环引用。

  • 不要用原始指针初始化多个shared_ptr。否则会多次释放同一块内存。

#include <iostream>
#include <memory>

int main() {
    {
        int a = 10;
        std::shared_ptr<int> ptra = std::make_shared<int>(a);
        //std::shared_ptr<int> ptra1 = std::make_shared<int>(a);//不要初始化多个,会出错。
        std::shared_ptr<int> ptra2(ptra); //copy
        std::cout << ptra.use_count() << std::endl;

        int b = 20;
        int *pb = &a;
        //std::shared_ptr<int> ptrb = pb;  //error
        std::shared_ptr<int> ptrb = std::make_shared<int>(b);
        ptra2 = ptrb; //assign
        pb = ptrb.get(); //获取原始指针
        std::cout << ptra.use_count() << std::endl;
        std::cout << ptrb.use_count() << std::endl;
    }
}

unique_ptr

和shared_ptr不一样,不能拷贝。只能移动。同一时间只能有一个unique_ptr指向一个对象。

#include <iostream>
#include <memory>

int main() {
    {
        std::unique_ptr<int> uptr(new int(10));  //绑定动态对象
        //std::unique_ptr<int> uptr2 = uptr;  //不能賦值
        //std::unique_ptr<int> uptr2(uptr);  //不能拷貝
        std::unique_ptr<int> uptr2 = std::move(uptr); //轉換所有權
        uptr2.release(); //释放所有权
    }
    //超過uptr的作用域,內存釋放
}

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。

使用的时候要检查是否为空。

如何使用

创建

std::shared_ptr<int> p1;             //不传入任何实参
std::shared_ptr<int> p2(nullptr);    //传入空指针 nullptr
std::shared_ptr<int> p3(new int(10));
std::shared_ptr<int> p3 = std::make_shared<int>(10);
//调用拷贝构造函数
std::shared_ptr<int> p4(p3);//或者 std::shared_ptr<int> p4 = p3;
//调用移动构造函数,因为move是非原子性的,比拷贝这个原子性的操作更快
std::shared_ptr<int> p5(std::move(p4)); //或者 std::shared_ptr<int> p5 = std::move(p4);

智能指针带来了什么问题

问题

解决方案


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!