智能指针(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 阅读点滴记录(二)的更多相关文章

  1. C++primer 阅读点滴记录(三)

    14章 操作符重载和转换 重载操作符是具有特殊名称的函数:保留字operator后接需要定义的操作符符号. 1.重载的操作符名: + – * / % ^ & | ~ ! , = <  & ...

  2. C++primer 阅读点滴记录(一)

    第十三章 复制控制:(copy control) 复制构造函数(copy constructor) 复制操作符(assignment operator) ps: 什么时候需要显示的定义复制控制操作:类 ...

  3. Hadoop阅读笔记(二)——利用MapReduce求平均数和去重

    前言:圣诞节来了,我怎么能虚度光阴呢?!依稀记得,那一年,大家互赠贺卡,短短几行字,字字融化在心里:那一年,大家在水果市场,寻找那些最能代表自己心意的苹果香蕉梨,摸着冰冷的水果外皮,内心早已滚烫.这一 ...

  4. 【转】Tomcat总体结构(Tomcat源代码阅读系列之二)

    本文是Tomcat源代码阅读系列的第二篇文章,我们在本系列的第一篇文章:在IntelliJ IDEA 和 Eclipse运行tomcat 7源代码一文中介绍了如何在intelliJ IDEA 和 Ec ...

  5. Material Calendar View 学习记录(二)

    Material Calendar View 学习记录(二) github link: material-calendarview; 在学习记录一中简单翻译了该开源项目的README.md文档.接下来 ...

  6. ZooKeeper源码阅读——client(二)

    原创技术文章,转载请注明:转自http://newliferen.github.io/ 如何连接ZooKeeper集群   要想了解ZooKeeper客户端实现原理,首先需要关注一下客户端的使用方式, ...

  7. Linux协议栈代码阅读笔记(二)网络接口的配置

    Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...

  8. Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客

    ==他的博客应该不错,没有细看 Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客 http://blog.csdn.net/u012706811/article/det ...

  9. Apollo源码阅读笔记(二)

    Apollo源码阅读笔记(二) 前面 分析了apollo配置设置到Spring的environment的过程,此文继续PropertySourcesProcessor.postProcessBeanF ...

随机推荐

  1. WPF更新数据源

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windo ...

  2. maven Spring获取不到配置文件

    如题: 如果在maven项目中,Spring获取不到配置文件, 把配置文件放到.src/main/resource文件夹下即可 import org.springframework.context.s ...

  3. Java基础知识:序列化和反序列化

    一.序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化. 把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬盘上,通常存 ...

  4. Android——TableLayout

    TableLayout的行数由开发人员直接指定,即有多少个TableRow对象(或View控件),就有多少行. TableLayout的列数等于含有最多子控件的TableRow的列数.如第一Table ...

  5. css选择器nth-child()和nth-of-type()的应用

    <style> .table-striped tbody > tr:nth-child(odd) > td, .table-striped tbody > tr:nth- ...

  6. LibreOffice源码编译以及生成VS项目

    最权威的社区链接:https://wiki.documentfoundation.org/Development/BuildingOnWindows 也许英文好的人直接看wiki上的说明就能很容易的编 ...

  7. php array(object) 与xml相互转换

    private function _array_to_xml($source, $charset='utf-8'){ $array = json_decode($source); $pre = '&l ...

  8. 洛谷P1206 [USACO1.2]回文平方数 Palindromic Squares

    P1206 [USACO1.2]回文平方数 Palindromic Squares 271通过 501提交 题目提供者该用户不存在 标签USACO 难度普及- 提交  讨论  题解 最新讨论 暂时没有 ...

  9. JDBC链接MySQL和Oracle

    import java.sql.*;         JDBC中所要用的包几乎都在import?java.sql.*;中: 在项目中导入Oracel或者是MySQL包和装载驱动:     项目的Cla ...

  10. jqmobi 的一些設置

    jqmobi version=2.1; 不是 version =3.0: 好吧,我用了jqmobi 差不多半年了,我竟然連 官方的文檔都沒有看完,怪不得我走了多少的彎路.....哎!!!! 1.隱藏 ...