教程集 www.jiaochengji.com
教程集 >  脚本编程  >  C语言  >  正文 c 11教程 智能指针讲解

c 11教程 智能指针讲解

发布时间:2018-09-10   编辑:jiaochengji.com
教程集为您提供c 11教程 智能指针讲解等资源,欢迎您收藏本站,我们将为您提供最新的c 11教程 智能指针讲解资源
智能指针(smart pointer)的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象的指针指向同一对象。

如果在程序中使用new从堆(自由存储区)分配内存,等到不需要时, 应使用delete将其释放。c 引入了智能指针auto_ptr, 以帮助自动完成这个过程。 c 11摒弃了auto_ptr,并新增了三种智能指针:unique_ptr, shared_ptr, weak_ptr。

一. auto_ptr, unique_ptr , shared_ptr

头文件:  #include <memory>

用法:
auto_ptr<double>  A(new double);
unique_ptr<int>    B( new int);
shared_ptr<string> C(new string>;

<pre class="brush:cpp;toolbar:false">#include <iostream>   #include <memory>   #include <string>   using namespace std;   class Report   {       public:         Report(const string s) : str(s)         {             cout << "Object create!\n";          }            ~Report() { cout << "Object deleted!\n"; }                  void comment() const { cout << str << endl; }                  private:           string str;   };      int main()   {       {           auto_ptr<Report> ps (new Report("using auto_ptr"));           ps->comment();       }          {           shared_ptr<Report> ps (new Report("using shared_ptr"));           ps->comment();       }          {           unique_ptr<Report> ps (new Report("using unique_ptr"));           ps->comment();       }          return 0;   }</pre>



运行结果:

01.png


所有的只能指针类都有一个explict构造函数,该构造函数可以将指针作为参数, 因此不需要自动将指针转换为智能指针对象。

shared_ptr<double> p;

double* q =  new double;

p = q; //not allowed, implicit conversion

pd = shared_ptr<double> (q);  //ok, explict conversion


智能指针和常规指针类似, 也能执行 解引用操作(*p), 访问结构成员 (p -> m_), 将它赋值给同类型的常规指针。 还可以将智能指针对象赋给另一个同类型的智能指针对象。


智能指针应避免如下操作:

string str("hehe");

shared_ptr<string> A(&str);  //NO!

ptr过期时,程序将把delete运算符用于非堆内存,这是错误的。


二.

对于指向在堆分配的内存的指针, 指针间赋值是不能接受的,因为程序将试图删除同一个对象两次。

要避免这种问题,方法有多种:

1. 定义赋值运算符,使之执行深复制。 这样两个指针将指向不同对象, 其中一个对象是另一个的副本。

2. 建立所有权概念, 对于特定对象, 只有一个智能指针可以拥有他 ,这样只有拥有对象的智能指针的构造函数会删除对象。 然后, 让赋值操作转让所有权 。 这是用于

auto_ptr 和 unique_ptr的策略, 但unique_ptr的策略更严格。

3. 创建智能更高的指针,跟踪引用特定对象的智能指针数。 这称为引用计数。 例如,赋值时, 计数加1, 指针过期时,计数减1, 仅当最后一个指针过期时,才调用delete。这是shared_ptr 采用的策略。


 auto_ptr<string> p1(new string("auto");

 auto_ptr<string> p2;

p2 = p1;   //OK

p2接管p1所有权后,p1的所有权将被剥夺。 这样可以防止p1 和 p2的析构函数试图删除同一个对象 。 但如果随后试图使用p1, 这将是件坏事, 因为p1不在指向有效的数据。


但是如果把上面的auto_ptr换成unique_ptr,编译器会认为 p2 = p1;这句是非法的,这样避免了p1不在指向有效数据的问题, 因为unique_ptr比auto_ptr更安全。

weak_ptr是为配合shared_ptr而引入的一种智能指针来协助shared_ptr工作,它可以从一个shared_ptr或另一个weak_ptr对象构造,它的构造和析构不会引起引用记数的增加或减少。没有重载*和->但可以使用lock获得一个可用的shared_ptr对象
weak_ptr的一个重要用途是通过lock获得this指针的shared_ptr,使对象自己能够生产shared_ptr来管理自己,但助手类enable_shared_from_this的shared_from_this会返回this的shared_ptr,只需要让想被shared_ptr管理的类从它继承即可。



C 11能用智能指针  

智能指针是基于RAII机制实现的类(模板),具有指针的行为(重载了operator*与operator->操作符),可以“智能”地销毁其所指对象。C 11中有unique_ptr、shared_ptr与weak_ptr等智能指针,可以对动态资源进行管理。

也就是带引用计数,并且能自动释放内存的智能指针包括以下几种:
unique_ptr: 如果内存资源的所有权不需要共享,就应当使用这个(它没有拷贝构造函数),但是它可以转让给另一unique_ptr(存在move构造函数)。
shared_ptr: 如果内存资源需要共享,那么使用这个(所以叫这个名字)。
weak_ptr: 持有被shared_ptr所管理对象的引用,但是不会改变引用计数值。它被用来打破依赖循环(想象在一个tree结构中,父节点通过一个共享所有权的引用(chared_ptr)引用子节点,同时子节点又必须持有父节点的引用。如果这第二个引用也共享所有权,就会导致一个循环,最终两个节点内存都无法释放)。
值得注意的是,auto_ptr已经被废弃,不会再使用了。

1、unique_ptr 智能指针使用

<pre class="brush:cpp;toolbar:false">// 智能指针的创建  std::unique_ptr<MyClass> mc(new MyClass); mc.reset(new MyClass);    // "绑定"动态对象;并释放之前"绑定"的对象。 std::unique_ptr<MyClass> mmc(new MyClass); mmc    = std::move(mc);    // mmc原"绑定"对象,被释放,mmc重新"绑定"到mc的"绑定"的对象,变成空的智能指针. mmc = nullptr;            // 显式销毁所指对象,同时智能指针变为空指针。与u_s2.reset()等价   mc.reset(new MyClass);    // "绑定"动态对象; if (mmc==nullptr) {     mmc = std::move(mc); }</pre>


2、unique_ptr的使用场景

(1) 动态资源的异常安全保证(利用其RAII特性):
void foo()  
{//异常安全的代码。无论是否异常发生,只要px指针成功创建,其析构函数都会被调用,确保动态资源被释放  
    unique_ptr<X> px(new X);  
    // do something,  自动释放资源。
}
(2) 返回函数内创建的动态资源
unique_ptr<X> foo()  
{  
    unique_ptr<X> px(new X);  
    // do something  
    return px; //移动语义  
}
std::unique_ptr<MyClass> mmcn = foo();

(3) 可放在容器中(弥补了auto_ptr不能作为容器元素的缺点)
方式一:
vector<unique_ptr<string>> vs { new string{“Doug”}, new string{“Adams”} };
方式二:
vector<unique_ptr<string>>v;
unique_ptr<string> p1(new string("abc"));
v.push_back(std::move(p1));//这里需要显式的移动语义,因为unique_ptr并无copy语义
(4) 管理动态数组,因为unique_ptr有unique_ptr<X[]>重载版本,销毁动态对象时调用delete[]
unique_ptr<int[]> p (new int[3]{1,2,3});
p[0] = 0;// 重载了operator[]

3、shared_ptr智能指针使用

<pre class="brush:cpp;toolbar:false">shared_ptr的方法多一点,简单一些。 {     std::shared_ptr<MyClass> myDevice;    // 智能指针的创建      std::shared_ptr<MyClass> device = std::make_shared<MyClass>();    // 智能指针的创建并指向对象,引用为1.     if (!myDevice.unique())     {         myDevice = device;    // 引用 1;则2.     } }// 释放内存</pre>


您可能感兴趣的文章:
c 11教程 智能指针讲解
如何区分C/C 常量指针和指针常量
小甲鱼的python讲的如何
photoshop智能对象使用经验技巧
为什么python慢
超详细的C 指针介绍及实例教程
从零开始学习jQuery (一) 开天辟地入门篇
photoshop智能美肤后期修图教程
C语言中函数 与 指针学习笔记
指针和参数传递(Go语言)

[关闭]
~ ~