C++primer 阅读点滴记录(二)
智能指针(smart point)
除了增加功能外,其行为像普通指针一样。 一般通过使用计数(use count)或引用计数(reference count)实现智能指针,防止出现指针垂悬。
下面是一个普通带指针的类代码:
#ifndef HASPTR_H
#define HASPTR_H class HasPtr{
public:
HasPtr(int *p, int i):ptr(p),val(i){}
int *get_ptr()const{return ptr;}
int get_int()const{return val;} void set_ptr(int *p){ptr = p;}
void set_int(int i){val = i;} int get_ptr_val()const{return *ptr;}
void set_ptr_val(int val)const{ *ptr = val;}
private:
int *ptr; //common pointer
int val;
}; #endif // HASPTR_H
小心地雷:
具有指针成员且使用默认合成构造函数的类具有普通指针的所有缺陷。尤其是,类本身无法避免垂悬指针。
一般有两种策略使用引用计数:
1、单独定义一个具体类用以封装使用计数和相关指针:(一般将该类设为私有类,仅友元类可以访问)
//private class for use by HasPtr only
class U_ptr{
friend class HasPtr;
int *ip;
size_t use;
U_ptr(int* p):ip(p),use(1){}
~U_ptr(){delete ip;}
}; HasPtr& HasPtr::operator =(const HasPtr& rhs){
++rhs.ptr->use;//increment use count on rhs first
if(--ptr->use == 0) //if use count goes to 0 on this object, delete it
delete ptr;
ptr = rhs.ptr;//copy the U_ptr
val = rhs.val;//copy the int member
return *this;
}
下面是原来的HasPtr类
class HasPtr{
public:
//HasPtr owns the pointer, p must been dynamically allocalted
HasPtr(int *p, int i):ptr(new U_ptr(p)),val(i){}
//copy memebers and increment the use count
HasPtr(const HasPtr& orig):
ptr(orig.ptr),val(orig.val){ ++ptr->use;}
HasPtr& operator=(const HasPtr&);
//if use count goes zero, delete th U_ptr object
~HasPtr(){
if (--ptr->use == 0)
delete ptr;
}
int *get_ptr()const{return ptr->ip;}
int get_int()const{return val;}
void set_ptr(int *p){ptr->ip = p;}
void set_int(int i){val = i;}
int get_ptr_val()const{return *ptr->ip;}
void set_ptr_val(int val){*ptr->ip = i;}
private:
U_ptr* ptr;
int val;
};
复制操作比复制构造函数要复杂点,一般现将右操作数引用计数加1, 然后左操作数对象引用计数减1并检查这个引用计数。
HasPtr& HasPtr::operator =(const HasPtr& rhs){
++rhs.ptr->use;//increment use count on rhs first
if(--ptr->use == 0) //if use count goes to 0 on this object, delete it
delete ptr;
ptr = rhs.ptr;//copy the U_ptr
val = rhs.val;//copy the int member
return *this;
}
注解: 这个赋值操作符在减少左操作数的使用计数之前使rhs的使用计数加1,从而防止自身赋值。
现在需要改变访问int*的其他成员,以便通过U_ptr指针简洁获取int
定义值类型:
处理指针成员的另一种完全不同的方法,是给指针成员提供值语义(value semantics), 复制值对象时,会得到一个不同的新副本。对副本的操作不会反映到原有对象上,反之亦然。
代码示例如下:
#ifndef VALUE_PTR_H
#define VALUE_PTR_H class HasPtr{
public:
HasPtr(const int&p, int i):ptr(new int(p)),val(i){}
HasPtr(const HasPtr& orig):ptr(new int(*orig.ptr)),val(orig.val){}
HasPtr& operator=(const HasPtr&);
~HasPtr(){delete ptr;} int get_ptr_val()const{return *ptr;}
int get_int()const{return val;} void set_ptr(int* p){ptr = p;}
void set_int(int i){val = i;} int* get_ptr()const{return ptr;}
void set_ptr_val(int val){*ptr = val;}
private:
int* ptr;
int val;
}; HasPtr& HasPtr::operator =(const HasPtr& rhs){
*ptr = *rhs.ptr; //copy the value pointer to
val = rhs.val; //copy the int
return *this;
}
#endif // !VALUE_PTR_H
注解: 即使要讲一个对象赋值给它本身,赋值操作符也必须总是保证正确。 本例中,即使左右操作数相同,操作本质上也是安全的,因此,不需要显示检查自身赋值。
C++primer 阅读点滴记录(二)的更多相关文章
- C++primer 阅读点滴记录(三)
14章 操作符重载和转换 重载操作符是具有特殊名称的函数:保留字operator后接需要定义的操作符符号. 1.重载的操作符名: + – * / % ^ & | ~ ! , = < & ...
- C++primer 阅读点滴记录(一)
第十三章 复制控制:(copy control) 复制构造函数(copy constructor) 复制操作符(assignment operator) ps: 什么时候需要显示的定义复制控制操作:类 ...
- Hadoop阅读笔记(二)——利用MapReduce求平均数和去重
前言:圣诞节来了,我怎么能虚度光阴呢?!依稀记得,那一年,大家互赠贺卡,短短几行字,字字融化在心里:那一年,大家在水果市场,寻找那些最能代表自己心意的苹果香蕉梨,摸着冰冷的水果外皮,内心早已滚烫.这一 ...
- 【转】Tomcat总体结构(Tomcat源代码阅读系列之二)
本文是Tomcat源代码阅读系列的第二篇文章,我们在本系列的第一篇文章:在IntelliJ IDEA 和 Eclipse运行tomcat 7源代码一文中介绍了如何在intelliJ IDEA 和 Ec ...
- Material Calendar View 学习记录(二)
Material Calendar View 学习记录(二) github link: material-calendarview; 在学习记录一中简单翻译了该开源项目的README.md文档.接下来 ...
- ZooKeeper源码阅读——client(二)
原创技术文章,转载请注明:转自http://newliferen.github.io/ 如何连接ZooKeeper集群 要想了解ZooKeeper客户端实现原理,首先需要关注一下客户端的使用方式, ...
- Linux协议栈代码阅读笔记(二)网络接口的配置
Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...
- Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客
==他的博客应该不错,没有细看 Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客 http://blog.csdn.net/u012706811/article/det ...
- Apollo源码阅读笔记(二)
Apollo源码阅读笔记(二) 前面 分析了apollo配置设置到Spring的environment的过程,此文继续PropertySourcesProcessor.postProcessBeanF ...
随机推荐
- dd 命令实时进度监控
dd脚本: #!/bin/sh if [ -d "${1}" ]; then echo "!mkdir" else } fi cd ${} name=`date ...
- UIButton 详解
1)创建 UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 风格有如下 typedef enum { UIButt ...
- LLDB命令查看内存的分配历史
(lldb) script import lldb.macosx.heap(lldb) malloc_info --stack-history 0x10010d680
- Android下实现控件的叠加显示
<FrameLayout android:layout_width="fill_parent" android:layout_height="match_paren ...
- [ CodeVS冲杯之路 ] P1368
不充钱,你怎么AC? 题目:http://codevs.cn/problem/1368/ 嗯……泡泡堂,很劲啊,其实就是个盗版的田忌赛马 http://www.cnblogs.com/hyfer/p/ ...
- 简单的as3操作xml
package { import flash.display.Sprite; import flash.events.Event; import flash.net.URLLoader; import ...
- OSGI.NET mainfest.xml 配置
在使用 OSGI.NET进行插件式的开发时,需要对 Mainfest.xml 进行配置, Mainfest 文件是插件的重要配置文件,其中暴露了插件启动方式以及插件启动时所依赖的程序集或其它资源的信息 ...
- 学习总结 java基础
- Hadoop SecondaryNameNode备份及恢复
1.同步各个服务器时间 yum install ntp ntpdate ntp.fudan.edu.cn hdfs-site.xml配置 如果没有配置这一项,hadoop默认是0.0.0.0:5009 ...
- CSS 居中效果完整指南
本文翻译自:<Centering in CSS: A Complete Guide> 使用 CSS 实现效果困难吗?显然不是.实际上有许多方法可以实现居中效果,但在具体情况中,我们往往无法 ...