C++11三种智能指针使用 原创 C++开发 2022年7月12日 14:40 夏至未至 1009 当前内容 3797 字,在路上,马上到,马上到 ## 目录 [TOC] ## 原理介绍 智能指针不是一个指针,它其实是一个对象。它是通过[C++的RAII机制](https://www.codecomeon.com/posts/200/ "C++的RAII机制")实现的。主要是利用C++中对象在释放的时候,会自动调用析构函数这一特性。所以,当智能指针对象释放的时候,在智能指针对象的析构函数中来释放其管理的内存资源。这样,开发人员就不需要手动去释放已经分配的内存空间。 这里介绍 C++11 中三种智能指针:`shared_ptr`、`unique_ptr`、`weak_ptr`,C++11 前的 auto_ptr,过时不究。 ## 三种指针详解 ### unique_ptr unique_ptr 是一个独享所有权的智能指针,它提供了严格意义上的所有权,无法进行复制构造,无法进行复制赋值操作。即无法使两个unique_ptr指向同一个对象。但是可以进行移动构造和移动赋值操作保存指向某个对象的指针,当它本身被删除释放的时候,会使用给定的删除器释放它指向的对象。 #### 初始化 //通过构造函数初始化 unique_ptr t(new Test()); //使用make_unique来初始化智能指针 unique_ptr t = make_unique(); #### 获取原始指针 unique_ptr t(new Test()); Test* pTest = t.get(); #### 支持所有权转移 unique_ptr不支持拷贝、赋值,但支持所有权转移,即智能指针将当前所指的内存空间的所有权交给另一个智能指针。被管理的内存空间永远只有一个智能指针指向它。 unique_ptr t(new Test()); unique_ptr t1 = move(t); ### shared_ptr shared_ptr是智能指针的一种,不仅通过RAII机制来管理内存资源,还引入了引用计数来解决当多个智能指针指向同一块内存空间的时候,何时释放这块内存空间的问题。也就是说,同一时刻可以有多个shared_ptr拥有一块内存空间的所有权,当最后一个shared_ptr被销毁时,这块内存空间的引用计数为0时,这块内存空间将被释放。 #### 初始化 //通过构造函数初始化 shared_ptr t(new Test()); //使用make_shared来初始化智能指针 shared_ptr t = make_shared(); #### 获取原始指针 shared_ptr t = make_shared(); Test* pTest = t.get(); #### 支持拷贝构造和赋值 shared_ptr t(new Test()); shared_ptr t1(t); t1 = t; ### weak_ptr weak_ptr和shared_ptr、unique_ptr不同,weak_ptr不能单独作为智能指针使用。weak_ptr是用来辅助shared_ptr来解决循环引用的问题,它指向一个由 shared_ptr 管理的对象而不影响所指对象的生命周期,也就是将一个 weak_ptr 绑定到一个 shared_ptr 不会改变 shared_ptr 的引用计数。不论是否有 weak_ptr 指向,一旦最后一个指向对象的 shared_ptr 被销毁,对象就会被释放。从这个角度看,weak_ptr更像是shared_ptr的一个助手而不是智能指针。 #### 初始化 创建一个weak_ptr时,需要用一个 shared_ptr 实例来初始化 weak_ptr,由于是弱共享,weak_ptr 的创建并不会影响 shared_ptr 的引用计数值: int main() { shared_ptr sp(new int(5)); cout << "创建前sp的引用计数:" << sp.use_count() << endl; // use_count = 1 weak_ptr wp(sp); cout << "创建后sp的引用计数:" << sp.use_count() << endl; // use_count = 1 } #### 判断指向对象是否存在 既然weak_ptr并不改变其所共享的shared_ptr实例的引用计数,那就可能存在weak_ptr指向的对象被释放掉这种情况。这时,我们就不能使用weak_ptr直接访问对象。那么我们如何判断weak_ptr指向对象是否存在呢?C++中提供了`lock`函数来实现该功能。如果对象存在,lock()函数返回一个指向共享对象的shared_ptr,否则返回一个空shared_ptr。 class A { public: A() : a(3) { cout << "A Constructor..." << endl; } ~A() { cout << "A Destructor..." << endl; } int a; }; int main() { shared_ptr sp(new A()); weak_ptr wp(sp); sp.reset(); if (shared_ptr pa = wp.lock()) { cout << pa->a << endl; } else { cout << "wp指向对象为空" << endl; } } 除此之外,weak_ptr还提供了`expired()`函数来判断所指对象是否已经被销毁。 class A { public: A() : a(3) { cout << "A Constructor..." << endl; } ~A() { cout << "A Destructor..." << endl; } int a; }; int main() { shared_ptr sp(new A()); weak_ptr wp(sp); sp.reset(); // 此时sp被销毁 cout << wp.expired() << endl; // true表示已被销毁,否则为false } #### 如何使用 weak_ptr并没有重载 `operator->`和 `operator *`操作符,因此不可直接通过`weak_ptr`使用对象,典型的用法是调用其 `lock` 函数来获得 `shared_ptr` 示例,进而访问原始对象。最后,我们来看看如何使用weak_ptr来改造最前面的代码,打破循环引用问题。 class ClassB; class ClassA { public: ClassA() { cout << "ClassA Constructor..." << endl; } ~ClassA() { cout << "ClassA Destructor..." << endl; } weak_ptr pb; // 在A中引用B }; class ClassB { public: ClassB() { cout << "ClassB Constructor..." << endl; } ~ClassB() { cout << "ClassB Destructor..." << endl; } weak_ptr pa; // 在B中引用A }; int main() { shared_ptr spa = make_shared(); shared_ptr spb = make_shared(); spa->pb = spb; spb->pa = spa; } 输出: ClassA Constructor... ClassB Constructor... ClassB Destructor... ClassA Destructor... E:\Learn\NormalTest\Debug\NormalTest.exe (进程 19840)已退出,代码为 0。 按任意键关闭此窗口. . . 本文标题: C++11三种智能指针使用 本文作者: 夏至未至 发布时间: 2022年7月12日 14:40 最近更新: 2022年7月12日 21:14 原文链接: 许可协议: 署名-非商业性-禁止演绎 4.0 国际(CC BY-NC-ND 4.0) 请按协议转载并保留原文链接及作者 C++开发(12) RAII(2) 上一个 优秀火车票订票系统(内附论文) 下一个 MySQL视图-增删改查 当前文章评论暂未开放,请移步至留言处留言。