【M28】智能指针
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】智能指针的更多相关文章
- C++ 智能指针auto_ptr
template<class T> class auto_ptr { public: ); // Item M5 有“explicitfor”// 的描述 template<clas ...
- enote笔记法使用范例(2)——指针(1)智能指针
要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...
- C++11 shared_ptr 智能指针 的使用,避免内存泄露
多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...
- C++智能指针
引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...
- EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针
一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...
- 智能指针shared_ptr的用法
为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...
- 智能指针unique_ptr的用法
unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...
- 基于C/S架构的3D对战网络游戏C++框架_05搭建系统开发环境与Boost智能指针、内存池初步了解
本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...
- C++ 引用计数技术及智能指针的简单实现
一直以来都对智能指针一知半解,看C++Primer中也讲的不够清晰明白(大概是我功力不够吧).最近花了点时间认真看了智能指针,特地来写这篇文章. 1.智能指针是什么 简单来说,智能指针是一个类,它对普 ...
随机推荐
- Oracle数据库中有关记录个数的查询
一.查询表中全部的记录个数 可用两种方法,一种是在oracle的系统表中统计,另一种需要写存储过程统计,方法分别如下. 1.系统表中统计: SELECT sum(num_rows) FROM user ...
- android启动页优化实践
最近观看友盟统计发现App启动页跳出率很高,观看启动页的平均启动时间为2.8s,如下图: 所以一个很现实的问题就出来了,优化启动页面... (一)做了什么? 我们的启动页面主要用于展示启动页面,加载网 ...
- Windows下安装GTK+
Step 1:到GTK官方网站上下载安装包.有32位的和64位,64位的有这句: Note that these 64-bit packages are experimental. Binary co ...
- python3 多线程的基本用法
#coding=utf-8 import threading #导入threading包 from time import sleep import time def task1(): p ...
- 关于Activity的少许细节
1. 对活动应用样式和主题 2. 隐藏活动标题 3. 显示对话框窗口 4. 显示进度对话框 1. 应用样式和主题 改成 android:theme="@android:style/Th ...
- 哈希(Hash)与加密(Encrypt)的基本原理、区别及工程应用
0.摘要 今天看到吉日嘎拉的一篇关于管理软件中信息加密和安全的文章,感觉非常有实际意义.文中作者从实践经验出发,讨论了信息管理软件中如何通过哈希和加密进行数据保护.但是从文章评论中也可以看出很多朋友对 ...
- HDU ACM 1325 / POJ 1308 Is It A Tree?
Is It A Tree? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tot ...
- JQuery发送Put、Delete请求 - 摘自网络
DELETE: $.ajax({ url: '/script.cgi', type: 'DELETE', success: function(result) { // Do something wit ...
- 一、 使用存储过程实现数据分页(Sql Server 2008 R2)
1.废话不多说了,直接上代码.调用这个存储过程只需要传递 表名,排序字段,搜索字段,以及页码,页码数量,搜索值(可空) create PROCEDURE NewPage --通用的分页存储过程,百万数 ...
- CentOS(RedHat) 6.2 Samba share权限拒绝访问
在实现<CentOS(RedHat) 6.2下Samba配置>的过程中,发现CentOS 6.2的Samba share总是没有权限写文件,已经试过在Windows XP/Windows ...