1、什么是智能指针?

  所谓智能指针就是,看起来,用起来,感觉起来都像原始指针,但是提供了更多功能。

2、使用智能指针取代原始指针,可以获得更多的控制权。如下:

  a、在构造和析构的时候,可以做一些事。

  b、在复制和赋值的时候,可以做一些事。

  c、在解引用的时候,可以做一些事。

3、智能指针可以对不同类型的指针进行封装,因此智能指针是一个模板类。

4、智能指针对原始指针封装,内含一个原始指针,为了用起来像指针,重载->和*,->返回原始指针,*返回对象的引用,两个重载操作符都不改变智能指针,因此是const成员方法。

5、考虑auto_ptr,拥有权转移,auto_ptr的copy构造会修改rhs,因此rhs不是const T&,而是T&。C++默认是传值,导致拥有权转移,如果期望拥有权不转移,使用传引用。

6、解引用操作符*,必须返回引用,不能返回对象。因为解引用操作符,可能返回T的子类。如果返回对象,首先导致对象复制,其次可能照成对象切割,失去多态功能。

7、判断智能指针是否为NULL。对于原始指针,使用if(pa == null),但是对于智能指针,不能这样使用,因为智能指针是个对象。怎么解决这个问题呢?

  a、增加isNull方法,缺点是与原始指针的用法不一致。
  b、为了与原始指针的用法一致,增加隐式类型转换操作符,operator void*()。但是这会导致一个问题,任意两个智能指针,都能进行比较,因为他们都可以隐式转化为void*,这不是我们所期望的。

8、智能指针如何暴露出原始指针?

  使用&*pa,合法,先取引用,再取地址。但是这种写法太难看了。增加隐式类型转换操作符operator T*(),这会引入一个问题,不是我们期望的转换,编译器也会偷偷进行。使用get方法,返回原始指针,避免编译器偷偷地进行转换。
注意:暴露原始指针是危险的,因为暴露出去的原始指针,不再受控。比如:智能指针把资源delete了,外面的原始指针就是野指针了。或者外面的指针执行了delete,智能指针管理的指针指向垃圾。

9、考虑继承,C++是强制类型的。Smart_Ptr<Base>与Smart_Ptr<Derived>是两个完全不同的类,之间没有任何关系,更谈不上继承。那么问题来了,对于原始指针可以指向子类对象,而智能指针不行。如下:
  Base* b = new Derived(); // OK
  Smart_Ptr<Base> b = Smart_Ptr<Derived>(new Derived); //Error
  编译失败,这不合理,怎么解决这个问题呢?

10、首先想到的是,隐式类型转换。这显然不合理,对原始指针类型的所有转换都要考虑。

11、有没有更好的解决办法呢?

使用C++语言的新特性,成员方法模版。隐式类型转换操作符声明为成员方法模版,如下:
template <typename NewType>
operator Smart_Ptr<NewType>()
{
  return Smart_Ptr<NewType>(this->ptr);
}
考虑Smart_Ptr<Base> b = Smart_Ptr<Derived>(new Derived)的执行过程:
  a、编译器首先看看Smart_Ptr<Base>有没有一个构造方法,该构造方法只需要一个形参,形参类型为Smart_Ptr<Derived>,没有找到;
  b、编译器看看Smart_Ptr<Derived>有没有隐式类型转换操作符,将Smart_Ptr<Derived>转换为Smart_Ptr<Base>,没有找到;
  c、编译器尝试将成员方法模版实例化出来一个合适的方法,也就是一个隐式类型转换操作符,使得隐式类型转换成功。
将NewType实例化为模版实参Base,在return语句的构造方法中,使用原始指针Derived,初始化Base指针,构造出Smart_Ptr<Base>,当然可以。
  注意,这里还放大了权限,只要NewType指针可以转换为T指针,那么Smart_Ptr<NewType>对象就可以赋值给Smart_Ptr<T>对象。
  成员方法模版,还有两个问题。首先,考虑fun(Base&),fun(Derived&),对于Derived derived1, fun(derived1)的调用,fun(Derived&)的匹配程度更高。但是,对于成员方法模版,都可实例出一个方法,使得调用成功,并且匹配程度是一样的,这就导致不确定的调用,编译错误。其次,成员方法模版移植性不高,有些编译器不支持。

12、智能指针与const
  C++设计理念是,最小特权原则。让别人做一件事,尽量限制他的权利。一个典型的例子就是,C++在传递引用过程中,可以缩小权力,但不能放大权利。
  原始指针与const有两种关系:a、指向const对象的指针,不能修改指向的对象;b、指针常量,不能修改指向。因此,对于智能指针,我们也希望有这种弹性。但是,对于智能指针只有一个地方可以const,修饰智能指针对象,也就相当于修饰指针。那怎么样修饰指向的对象呢?使用Smart_Ptr<const T>。那么问题来了,Smart_Ptr<T> 与Smart_Ptr<const T>是两个完全不同的类型,当然不能赋值。该怎么办呢?不要再想着隐式类型转换了,因为隐式类型转换会导致非预期的转换。考虑里氏代换,子类能力更大。从const T 到T,是能力变大的过程,因此可以考虑Smart_Ptr<T>: Smart_Ptr<const T>

【M28】智能指针的更多相关文章

  1. C++ 智能指针auto_ptr

    template<class T> class auto_ptr { public: ); // Item M5 有“explicitfor”// 的描述 template<clas ...

  2. enote笔记法使用范例(2)——指针(1)智能指针

    要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...

  3. C++11 shared_ptr 智能指针 的使用,避免内存泄露

    多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...

  4. C++智能指针

    引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...

  5. EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针

    一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...

  6. 智能指针shared_ptr的用法

    为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...

  7. 智能指针unique_ptr的用法

    unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...

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

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  9. C++ 引用计数技术及智能指针的简单实现

    一直以来都对智能指针一知半解,看C++Primer中也讲的不够清晰明白(大概是我功力不够吧).最近花了点时间认真看了智能指针,特地来写这篇文章. 1.智能指针是什么 简单来说,智能指针是一个类,它对普 ...

随机推荐

  1. MongoDB之一介绍(MongoDB与MySQL的区别、BSON与JSON的区别)

    MySQL与MongoDB的操作对比,以及区别 MySQL与MongoDB都是开源的常用数据库,但是MySQL是传统的关系型数据库,MongoDB则是非关系型数据库,也叫文档型数据库,是一种NoSQL ...

  2. android面试题(转)

    1. Android dvm的进程和Linux的进程, 应用程序的进程是否为同一个概念 DVM指dalivk的虚拟机.每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚 ...

  3. Yii与表单交互的三种模式2

    在yii的标签中加入css或js方法:echo $form->textField($model,'starttime',array(        'onclick'=>'alert(&q ...

  4. 将数字映射到字母上 .xml

    映射成 A1------A20               B1------B20               ...               Z1------Z20 这种形式   数字从0开始编 ...

  5. vmware10中开启Intel VT-x

    记得刚接触linux的时候,是在win7下使用vmware虚拟机来安装linux,这样就可以方便的一边使用win7娱乐,一边在linux下进行学习.后来发现这种方式使得win7很卡,虚拟机也很卡,让人 ...

  6. 修改docker的默认存储位置

    service docker stop mv /var/lib/docker /mnt/docker ln -s /mnt/docker /var/lib/docker ls /var/lib/doc ...

  7. Java(jdk1.7) 陷阱

    String[] strA = new String[4]; for(int i=0; i<4; i++) { strA[i] = String.valueOf(i); } strA[0] = ...

  8. 20160512关于mac安装caffe的记录

    记得2015年在mac系统上安装过一次caffe,非常顺利,但是最近群里许多同学反映mac安装caffe出现了各种问题,同时我也在帮助别人安装caffe的时候也遇到了一些坑,不再像以前这么顺利了.估计 ...

  9. html5 canvas 鼠标绘制

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  10. 远控软件VNC攻击案例研究

    欢迎大家给我投票: http://2010blog.51cto.com/350944           本文出自 "李晨光原创技术博客" 博客,谢绝转载!