“智能指针”的成长

  智能指针是什么,他的真面目就是一个类生成的对象,这个类中包含了基本的重载->、*等一些指针形态的用法,最主要的是这个类里面有一个指针参数:所有智能指针类中都有一个explicit构造函数,以指针作为参数。比如auto_ptr的类模板原型为:

template<class T>

class auto_ptr{

  explicit auto_ptr(T* p = 0);

};

代码中构造函数用了explicit关键字主要是防止隐式转换,举个例子:

auto_ptr<double> pd;

double *p_reg = new double;

pd = p_reg;       //error

pd = shared_ptr<double>(p_reg);    //error

shared_ptr<double> pshared = p_reg;     //error

shared_ptr<double> pshared(p_reg);

上面解释了一下智能指针的本质是什么,那它有什么作用呢,看代码看不出来,但仔细想,作为一个类对象,创建时需要构造,那待生命周期结束,也是需要自动析构的,所以就带出了他的功能,就是为了保证其指向的New出来的对象,可以在生命周期结束时自动Delete,作为程序员我们都知道,Delete这个东西我们经常忘写不说,也在很多return的地方忽略了写Delete,这就导致了内存泄漏,很致命。

所以C++就提供了一种智能指针的模式去防止这种现象,现有最常用的智能指针,分别有 std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array、boost::weak_ptr这6个智能指针都有各自的使用范畴,话不多说,研究下就知道。

⑴ std::auto_ptr

  首先auto_ptr这个智能指针,属于STL,同属于STL的还有unique_ptr、shared_ptr等,感兴趣的可以去查查,但本文就不进行介绍了。先来看一段代码

class Simple {

public:

  Simple(int param = 0) {

    number = param;

    std::cout << "Simple: " << number << std::endl;

  }

  ~Simple() {

    std::cout << "~Simple: " << number << std::endl;

  }

  void PrintSomething() {

    std::cout << "PrintSomething: " << info_extend.c_str() << std::endl;

  }

  std::string info_extend;

  int number;

};

void fun()

{

  std::auto_ptr<Simple> ptr (new Simple(1));

  if(ptr.get())

  {

    ptr->PrintSomething();

    ptr.get()->info_extend = "Hello";

    (*prt)->info_extend = "World";

  }

}

上一段代码运行的结果为:

  Simple:1

  PrintSometing:

  ~Simple:1

这是最标准的一种智能指针的使用方法,对于auto_ptr这种智能指针也是完全能驾驭的,但假如我们在代码中加入另外几句

std::auto_ptr<Simple> ptr2;

ptr2 = ptr;

pt2->PrintSomething();

pt1->PrintSomething(); // 崩溃

如果将上面的代码加到程序中就会崩溃,为什么呢?看源码中,重载=时,进行了

reset(_Right.release());

继续向里执行release的代码

可以看到,这里是将原本的指针控制权交给了别人,自身已经被置为NULL了。所以我们进行调用,不崩溃等什么呢?

然后加另一端代码:

if (ptr.get()) {

  ptr.release();

}

我们可以直接调用release函数,这就很尴尬了,直接返回值为当前指向的控制权,但没有指针接收,直接丢弃了,这就更尴尬了,导致只进行了构造,没有析构。。所以真要使用release函数的话,必须这样

Simple* ptr2 = ptr.release();

delete ptr2;

这恶心的用法总给人一种多此一举的做法,所以我release函数的直接使用是没有任何意义的。对于这种手动的释放内存,直接调用

ptr.reset();

所以我们对auto_ptr进行一个总结:

  1,尽量不要使用"="对智能指针进行赋值,如果使用,那先前对象就时一个空指针的。

  2,release函数单独使用没有任何意义,不会释放对象,还有可能导致对象丢失。他的作用仅仅是返回所有权。

  3,不要把智能指针对象当做参数传递进入函数,因为也会调用release,导致调用完函数,回来对象已经被析构。

  上述3个仅仅是个人发现的,对于auto_ptr本身就有很多不合理的地方,虽然还有人使用,但具体项目中用的已经不多了,所以就在auto_ptr的基础上,增加了各种其他的智能指针,用以修复这个使用不合理的地方。

⑵ boost::scoped_ptr

  scoped_ptr属于boost库,他与auto_ptr相比,也是避免了上述几个问题,主要的原因就是scoped的设计为独享所有权。主要的体现就是调用release函数和‘=’的时候是会报错的。虽然表面上的确是避免了auto_ptr中出现的问题,但种感觉是一种逃避的方法,那就有了下面的另一种智能指针。

⑶ boost::shared_ptr

  scoped_ptr属于boost库,与上述的scoped_ptr相比,它添加了共享所有权的功能,也就是可以使用‘=’方法,关于做法,原理就是在类中使用了一个引用计数,当进行赋值的时候对该数字加1,写一段代码看看:

void TestSharedPtr(boost::shared_ptr<Simple> ptr)

{

  std::cout << "TestSharedPtr2 UseCount: " << ptr.use_count() << std::endl;

}

boost::shared_ptr<Simple> ptr(new Simple(1));

std::cout << "TestSharedPtr2 UseCount: " << ptr.use_count() << std::endl;

{

  boost::shared_ptr<Simple> ptr2 = ptr;

  std::cout << "TestSharedPtr2 UseCount: " << ptr.use_count() << std::endl;

  TestSharedPtr(ptr);

  std::cout << "TestSharedPtr2 UseCount: " << ptr.use_count() << std::endl;

}

std::cout << "TestSharedPtr2 UseCount: " << ptr.use_count() << std::endl;

这一段代码运行下来的打印结果是:

TestSharedPtr2 UseCount: 1

TestSharedPtr2 UseCount: 2

TestSharedPtr2 UseCount: 3

TestSharedPtr2 UseCount: 2

TestSharedPtr2 UseCount: 1

大概解释一下,在开始只有一个ptr时,打印出来的引用计数为1,当另外使用一个ptr2时,再次打印出来为2,意思就是当前共有两个智能指针同时使用当前对象。进入函数后,又进行了一次拷贝构造到临时变量,所以打印值又变成3,后续退出函数和退出ptr2的生命周期,引用计数的值各剪了1,当代码执行完毕后,引用u计数值归0,调用析构函数时使用Delete释放空间。

⑷ boost::scoped_array

以数组的方式管理多个对象,但属性与scoped_ptr完全一致,独享所有权,而其使用方法也与数组没有太大的区别:

boost::scoped_array<Simple> ptr_array(new Simple[2]);

ptr_array[0].PrintSomething();

⑸ boost::shared_array

以数组的方式管理多个对象,属性与shared_ptr王权一致,共享所有权,内部使用引用计数

⑹ boost::weak_ptr

weak_ptr是一中比较特殊的智能指针,其应用的场景比较单一,主要是对shared_ptr进行观察的一种对象,也就是说用weak_ptr类型的对象对shared_ptr类型的对象进行引用,是可以正常访问,但不会改变后者的引用计数值,当后者被销毁后,前者也就不能使用了。现在说说它的应用场景,如果子类中有一个shared_ptr类型的对象,那基类中就可以定义一个weak_ptr类型的对象,通过访问基类的weak_ptr对象是否为空,就可以判断子类是否对自己进行赋值。

本文有部分函数名和编码方式是采用网上其他博主的风格(因为觉得这种讲解方法特别清晰,先简单介绍,然后上代码直接理解),所以有些抄袭的嫌疑,但全部均本人理解,并重新编码之后写上去的,很多地方也是本人通过理解源码,写出来的部分东西,如果有误,请及时沟通修正。

时间: 2024-07-30 13:35:48

“智能指针”的成长的相关文章

基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): 1.实现基本通信框架,包括对游戏的需求分析.设计及开发环境和通信框架的搭建: 2.实现网络底层操作,包括创建线程池.序列化网络包等: 3.实战演练,实现类似于CS反恐精英的3D对战网络游戏: 技术要点:C++面向对象思想.网络编程.Qt界面开发.Qt控件知识.Boost智能指针.STL算法.STL.

智能指针的原理和简单实现

什么是智能指针? 智能指针实质上是一个类,定义一个类来封装资源的分配和释放.这个类的构造函数中传入一个指针,完成资源的分配和初始化.在析构函数中释放传入的该指针,完成资源的释放. 为什么要用智能指针? 智能指针就是智能,自动化的管理指针所指向的动态资源. 例如以下情况:代码中经常会忘记释放动态开辟的内存资源,导致内存泄露. // case1 void Test2() {  int* p1 = new int(2);  bool isEnd = true;  //...  if (isEnd)  

实战c++中的智能指针unique_ptr系列-- 使用std::unique_ptr代替new operator(错误:‘unique_ptr’ is not a member of ‘std’)

写了很多篇关于vector的博客,其实vector很便捷,也很简单.但是很多易错的问题都是vector中的元素为智能指针所引起的.所以决定开始写一写关于智能指针的故事,尤其是unique_ptr指针的故事. 这是个开始,就让我们使用std::unique_ptr代替new operator吧! 还是用程序说话: #include<iostream> int main() { while (true) int *x = new int; } 看下任务管理器中的内存: 此时使用智能指针unique

C++智能指针简单剖析

导读 最近在补看<C++ Primer Plus>第六版,这的确是本好书,其中关于智能指针的章节解析的非常清晰,一解我以前的多处困惑.C++面试过程中,很多面试官都喜欢问智能指针相关的问题,比如你知道哪些智能指针?shared_ptr的设计原理是什么?如果让你自己设计一个智能指针,你如何完成?等等--.而且在看开源的C++项目时,也能随处看到智能指针的影子.这说明智能指针不仅是面试官爱问的题材,更是非常有实用价值. 下面是我在看智能指针时所做的笔记,希望能够解决你对智能指针的一些困扰. 目录

boost智能指针使用

#include <iostream> #include <tr1/memory> #include <boost/scoped_ptr.hpp> //scoped_ptr还不属于tr1 #include <boost/scoped_array.hpp> //scored_array也不属于tr1 #include <boost/shared_array.hpp> //shared_array也不属于tr1 class CTest { publi

webkit智能指针 - RefPtr, PassRefPtr

历史 2005年之前,Webkit中很多对象都采用引用计数的方式.它们通过继承RefCounted]类模板来实现这种模式.RefCounted主要是实现了ref()和deref()两个函数.在需要引用对象时要调用ref()增加引用计数,在不再需要对象时,要调用deref()函数减少引用计数.ref()和deref()需要成对出现.这和使用new/delete一样,多调用.少调用.没调用的问题总是时有发生.如果能由编译器自动完成ref, deref的调用,C/C++编程的bug至少也可以减少一半以

智能指针tr1::shared_ptr、boost::shared_ptr使用

对于tr1::shared_ptr在安装vs同时会自带安装,但是版本较低的不存在.而boost作为tr1的实现品,包含 "Algorithms Broken Compiler Workarounds Concurrent Programming Containers Correctness and Testing Data Structures Domain Specific Function Objects and Higher-order Programming Generic Progra

C++ Primer笔记8_动态内存_智能指针

1.动态内存 C++中,动态内存管理是通过一对运算符完成的:new和delete.C语言中通过malloc与free函数来实现先动态内存的分配与释放.C++中new与delete的实现其实会调用malloc与free. new分配: 分配变量空间: int *a = new int; // 不初始化 int *b = new int(10); //初始化为10 string *str = new string(10, ); 分配数组空间: int *arr = new int[10];//分配的

C++之智能指针20170920

/******************************************************************************************************************/ 一.C++智能指针_自己实现智能指针 1.使用局部变量结合new的方式,防止new导致的内存泄漏 class sp { private: Person *p; public: sp() : p(0) {}//表明sp的构造函数 继承person的无参构造函数 sp(