C++ primer 之定义行为像指针的类

2023-10-26

提前声明 ,这是一篇水博!!!

1.使用智能指针实现:

#include <string>
#include <iostream>
#include <memory>
using namespace std ;
class HasPtr {
public:
    HasPtr(const std::string &s = std::string()) : ps(make_shared<string>(s)), i(0)  { } 

    HasPtr(const HasPtr& hp) : ps(hp.ps), i(hp.i) { 
        cout << " 拷 贝 构 造 函  数 " << endl ;  // 又多了一个对象使用 *ps 
    }
    HasPtr& operator=(const HasPtr &rhs){  
        cout << " 赋 值 运 算 符 " << endl  ;
        ps = rhs.ps ;
        i = rhs.i ;   
        return  *this;
    }
    ~HasPtr(){ }

    void print(){
        cout << "*ps ==  " <<*ps  << endl ;
        cout << "i ==  " << i  << endl ;
        cout <<  "ps 引用计数 ==  " <<ps.use_count() << endl << endl << endl;
    }
private:
    shared_ptr<string>  ps ; //定义智能指针
    int i ;  // 额外数据成员 
};
int main(void){
    HasPtr test1("liushengxi") ,test3("3333333") ;
    HasPtr test2(test1); 
    test1.print(); // 引用计数应该 == 2 
    test2.print(); // 引用计数应该 == 2 


    test3  = test1 ;  //对于这种情况,左边引用计数 -1 ,右边引用计数 +1  
    test1.print() ;  //引用计数应该 == 3 
    test3.print() ;  // 引用计数应该 == 3 ,
    //而此时test3 初始化时指向的字符串“33333” ,应该已经被销毁了,这是因为test3 的引用计数 == 0 了,智能指针自动销毁
    return 0 ;
}

运行结果:

这里写图片描述

2. 自己定义引用计数实现:

#include <string>
#include <iostream>
#include <memory>
using namespace std ;
class HasPtr {
public:
    HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0),use(new size_t(1)) { }
    HasPtr(const HasPtr& hp) : ps(new std::string(*hp.ps)), i(hp.i) ,use(hp.use) { 
        cout << " 拷 贝 构 造 函  数 " << endl ; //又多了一个对象使用 *ps ,use++ ;
        ++(*hp.use) ;
    }
    HasPtr& operator=(const HasPtr &rhs){  
        cout << "赋值运算符 " << endl ;
        ++*rhs.use ;
        --*use ;

        auto temp_ps =  new string( *rhs.ps) ;
        delete ps ;
        ps = temp_ps ;
        i = rhs.i ;   
        use = rhs.use ;

        return  *this;
    }
    ~HasPtr(){
        --(*use) ;
        if( *use == 0 )
            delete ps ,delete use ;
    }
    void print(){
        cout << *ps  << endl ;
        cout <<  i  << endl ;
        cout << *use << endl << endl << endl  ;
    }
private:
    std::string *ps ;
    int i ;
    size_t *use ; //记录有多少个对象共享 *ps 成员 
};
int main(void){
    HasPtr test1("liushengxi") ,test3("3333333") ;
    HasPtr test2(test1);
    test1.print(); //  2 
    test2.print(); //  2 

    test3  = test1 ; 
    test1.print() ; // 3
    test3.print() ;  

    return 0 ;
}

运行结果:

这里写图片描述

最后说一下什么叫行为像指针的类?什么叫行为像值的类?

1.首先解释行为像值,对于行为像值,实际上就是对于每一个已经实例化的类的对象,对于每一个类管理的资源(这里C++primer中是针对于可以动态分配内存的容器而言的,实际上应该所有非内置类型需要动态申请的类型都需要这么做),当对象与对象之间进行复制操作的时候,每个对象都保存有一份副本,使得当有一个对象中对应的成员占有的空间被释放的时候,对应赋值过的对象中的相应成员不受影响。实际上这样释放空间的过程不应该仅仅存在于析构函数中,在我们重载赋值操作符(=)的时候也应该有释放被赋值的对象原来占有的类外空间的步骤,每一个实例化的对象中都要存储一份对应的成员的话,就不能像行为像指针的类中赋值操作的那样直接指针等于指针的方式,因为在行为像值的类中是有专门的计数器的,而在行为像值的类中是没有的,所以不能用同样的指针,必须要开辟新的地址。

c++ primer 中的一个小例子
#include <string>
#include <iostream>
#include <memory>
using namespace std ;
class HasPtr {
public:
    HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) { }
    HasPtr(const HasPtr& hp) : ps(new std::string(*hp.ps)), i(hp.i) { 
        cout << " 拷 贝 构 造 函  数 " << endl ;
    }
    HasPtr& operator=(const HasPtr &rhs){ 
        cout << "赋值运算符 " << endl ;
        auto temp_ps =  new string( *rhs.ps) ;
        delete ps ;
        ps = temp_ps ;
        i = rhs.i ;   
        return  *this;
    }
    ~HasPtr(){
        delete ps ;
    }
    void print(){
        cout << *ps  << endl ;
        cout << i << endl ;
    }
private:
    std::string *ps ;
    int i ;
};
int main(void){
    HasPtr test1("liushengxi") ,test3("zuishuai");
    HasPtr test2(test1);
    test2.print();

    test2  = test2 ;
    test2.print();
}

需要说明的一点是:编写赋值运算符时的编码顺序一定是这个样子的(这样可以很优雅的解决对象赋予它自身的问题)

    1.将右侧对象拷贝拷贝到一个局部临时对象中
    2.销毁左侧运算对象现有成员
    3.将临时局部对象拷贝到左侧运算对象的成员

2.对于想要使类的行为像指针的话,就需要加入新的计数机制,解决的问题就是如果类中有上述所说的默认析构函数不能释放的资源的时候需要程序员自己决定什么时候进行资源的释放。那么这个时候的机制就有点类似于智能指针了,我们需要在类中加入一个私有成员用于引用计数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ primer 之定义行为像指针的类 的相关文章

  • 如何正确的关闭 MFC 线程

    前言 近日在网上看到很多人问及如何关闭一下线程 但是我看网上给出的并不详细 而且有些方法还是错误的 小弟在此拙作一篇 不谈别的 只谈及如何正确的关闭MFC的线程 至于Win32和C RunTime的线程暂不涉及 一 关于MFC的线程 MFC
  • C++ 拷贝构造函数和赋值运算符

    本文主要介绍了拷贝构造函数和赋值运算符的区别 以及在什么时候调用拷贝构造函数 什么情况下调用赋值运算符 最后 简单的分析了下深拷贝和浅拷贝的问题 拷贝构造函数和赋值运算符 在默认情况下 用户没有定义 但是也没有显式的删除 编译器会自动的隐式
  • fastcgi的环境变量

    FCGI ROLE RESPONDER SCRIPT FILENAME scripts 5 cgi QUERY STRING aaa 11111111111111 bbb 2222222222222222 ccc 3333333333333
  • [原]Pro*C介绍-内嵌SQL

    Translate by Z Jingwei Document address http www db stanford edu ullman fcdb oracle or proc html Pro C介绍内嵌SQL 概要 Pro C语法
  • SQL 查询指定行数的数据。

    今天遇到一个关于 查询指定行数的数据 的sql查询语句问题 突然发现以前没怎么接触过 刚才想起来了 赶紧看了下文档 又上网搜了下 有了下面的东西 不知道有没有什么地方不对 oracle 先看一下文档中关于any和all的例子 很不错噢 An
  • Qt5学习之路(vs2012下创建一个QT应用程序)2013-10-14

    刚开始学习QT在网上找的资料基本都是使用QT Create进行开发的 VS下开发的学习资料感觉很少很难找的到 视频教程也基本没看到过貌似 因为我们研发中心是使用MFC进行开发开发工具是VS2010 使用QT开发的话基本我们不会再使用QT C
  • 解决“17: 错误:程序中有游离的‘\240’,\302’

    参考链接 https blog csdn net asuphy article details 54602426 执行如下命令即可 sed i s o240 o302 g dy haikang test cpp
  • 写时拷贝技术(copy-on-write)

    传统的fork 系统调用直接把所有的资源复制给新创建的进程 这种实现过于简单并且效率低下 因为它拷贝的数据也许并不共享 更糟的情况是 如果新进程打算立即执行一个新的映像 那么所有的拷贝都将前功尽弃 Linux的fork 使用写时拷贝 cop
  • 简析多级指针解引用

    转自 简析多级指针解引用 指针是C语言中公认的最为强大的语法要素 但同时也是最难理解的语法要素 它曾给程序员带来了无数麻烦和痛苦 以致于在C语言之后诞生的很多新兴 语言中我们再也难觅指针的身影了 下面是一个最简单的C语言指针的例子 int
  • vector,list,deque区别

    http blog csdn net renkaihao article details 6803866 vector和built in数组类似 它拥有一段连续的内存空间 并且起始地址不变 因此它能非常好的支持随即存取 即 操作符 但由于它
  • C++中的RTTI

    文章目录 dynamic cast运算符 指针类型的dynamic cast 引用类型的dynamic cast typeid运算符 使用RTTI type info类 参考资料 RTTI Runtime Type Information
  • LeetCode题目笔记——17.19消失的两个数字

    文章目录 题目描述 题目难度 困难 方法一 暴力 代码 代码优化 方法二 数学方法 代码 总结 题目描述 题目直达 题目难度 困难 方法一 暴力 虽然题目说你能在 O N 时间内只用 O 1 的空间找到它们吗 但是也没有限制我们不能用暴力
  • 为何在新建STM工程中全局声明两个宏

    在uVision中新建STM32工程后 需要从STM32标准库中拷贝标准外设驱动到自己的工程目录中 此时需要在工程设置 gt C C 选项卡下的Define文本框中键入这两个全局宏定义 STM32F40 41xxx USE STDPERIP
  • 模板的完全特例化和部分特例化

    介绍 完全特例化就是类型完全明确的版本 而部分特例化指的是 只知道是几个参数的函数而不知道参数的类型 或者是只知道是引用或者是指针类型 而不知道具体是char 还是 int 模板特例化实例1 template
  • Public Private Protect Inheritance and access specifiers

    In the previous lessons on inheritance we ve been making all of our data members public in order to simplify the example
  • 【数据结构/C++】树和二叉树_二叉链表

    include
  • Java反序列化漏洞-CC1利用链分析

    文章目录 一 前置知识 1 反射 2 Commons Collections是什么 3 环境准备 二 分析利用链 1 Transform
  • C 语言运算符详解

    C 语言中的运算符 运算符用于对变量和值进行操作 在下面的示例中 我们使用 运算符将两个值相加 int myNum 100 50 虽然 运算符通常用于将两个值相加 就像上面的示例一样 它还可以用于将变量和值相加 或者将变量和另一个变量相加
  • C++ 中 const 和 constexpr 关键字解析:常量、函数和指针

    很多 C 的初学者看到 const 这个关键字的第一反应都是一头雾水 主要是因为 const 可 以出现在很多的位置 以及后面加入的 constexpr 更是常常感到困惑 今天就为大家一一解释出现它们的含义和以及作用 const 关键字 c
  • 在 OS X 上的 virtualenv 中安装 scrapy 加密时发生错误 [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我正在安装 scrapypip in virtualenv on OS X 10 11 当它安装密码学时 它说 buil

随机推荐

  • C语言函数不定参数实现方式

    函数如何实现不定参数 由于在C语言中没有函数重载 解决不定数目函数参数问题变得比较麻烦 即使采用C 如果参数个数不能确定 也很难采用函数重载 对这种情况 提出了指针参数来解决问题 1 va list 定义了一个指针arg ptr 用于指示可
  • 数据库设计规范(详细)

    数据规范化设计 一 数据规范化 仅有好的RDBMS并不足以避免数据冗余 必须在数据库的设计中创建好的表结构 Dr E F codd 最初定义了规范化的三个级别 范式是具有最小冗余的表结构 这些范式是 1 第一范式 1st NF First
  • linux配置浮动IP

    在高可用集群环境中 一般都需要使用浮动IP来实现web高可用 High Availability 浮动IP的概念以及为什么需要浮动IP请参考 浮动IP FLOAT IP 本篇文章主要讲实际操作步骤 可以是双机 也可以是多机 主服务器为172
  • VLOOKUP函数匹配结果不正确?错误结果是怎么得出来的?[已解决]

    匹配结果不正确主要是以下2个方面入手 是否是精确匹配 range lookup 参数为 FALSE或0 检查所有的数据是否带空格等 官方帮助文档 Microsoft Excel 中 VLOOKUP 函数的语法和用法 语法 VLOOKUP l
  • [yotroy.cool]WSL安装CUDA独显 PyTorch 深度学习环境配置,测速为什么要用WSL?

    个人博客https www yotroy cool 欢迎关注我哦 前言 为了预习大三课程 想提前学习下PyTorch 于是我遇到了神仙学习教程 动手学深度学习 同时以此为参考完成了环境配置 感谢大佬们无私奉献Thanks 本教程展示了独显w
  • 等精度测频的原理和基于FPGA的实现

    我们通过FPGA测量信号频率 一般来说有两种方案 传统测频法和等精度测频法 方案一 传统测频是在一段闸门时间内直接对输入信号的周期进行计数 也被叫做直接测频法 设闸门信号为gate 检测待测信号上升沿 然后判断gate是否为高电平 若为高电
  • 转置矩阵,逆矩阵和倒转置矩阵

    单位矩阵 转置矩阵 transpose matrix 在线性代数中 矩阵A的转置是另一个矩阵AT 也写做Atr tA或A 由下列等价动作建立 把A的横行写为AT的纵列 把A的纵列写为AT的横行 形式上说 m n矩阵A的转置是n m矩阵 fo
  • 【ctfshow】PHP特性2

    目录 web100 web101 web102 web103 web104 web105 web106 web107 web108 web109 web110 web100 include ctfshow php flag in class
  • ascii码图片

    铁臂阿童木 be be Nc R o uQ bo Jod e dd e d
  • lora模块学习一

    LoRa TM 调制解调器采用扩频调制和前向纠错技术 与传统的FSK或OOK调制技术相比 这种技术不仅扩大了无线通讯链路的覆盖范围 而且还提高了链路的鲁棒性 在设计中 可以通过调整扩频因子 SF 调制带宽 BW 和编码率 CR 三个关键设计
  • cuda-gdb 调试方法:cuda gdb中的可调参数

    cuda gdb 中存在一些可调的参数 可以通过 set cuda lt tunable name gt
  • php实现ETH原生签名交易sendRowTransaction

    文章目录 1 安装GMP 之前需要先安装m4 不然会出错 2 然后ubuntu安装gmp 3 然后安装PHP gmp扩展 4 安装scrypt 扩展 4 撤销sudoers文件写权限 命令 参考文章链接 1 安装GMP 之前需要先安装m4
  • window.location.href跳转带有token的新链接时显示空白页

    问题 从A平台跳到B平台并自动登录B平台 后端生成包含token的完整链接传给前端 前端window location href打开时页面显示空白页 手动刷新才会跳到新链接 原因 用window location href跳转新链接可能会带
  • JIO学习(一)输入流综述

    一 字节输入流 java io InputStream java lang Object java io InputStream 所有已实现的接口 Closeable 直接已知子类 AudioInputStream ByteArrayInp
  • Pinia从入门到精通

    一 为什么使用 Pinia Pinia 是 Vue 的专属状态管理库 它允许你跨组件或页面共享状态 如果你熟悉组合式 API 的话 你可能会认为可以通过一行简单的 export const state reactive 来共享一个全局状态
  • /dev/null 1 & 2的用法

    应用背景 devnull 1 2的介绍 把错误输出和标准输出都导入日志testlog里 屏蔽标准输出和错误输出信息 tee命令如何把标准输出和错误输出都导入testlog里 应用背景 如下例所示 aa是不识别的命令 在执行 test sh时
  • 模拟退火法、遗传算法求解多皇后问题

    一 问题背景 多皇后问题是一个经典的问题 在一个 N x N 的棋盘上放置 N 个皇后 使其不能互相攻击 每行 每列 每一斜线上分别只能放置一个皇后 求解 N 皇后问题的复杂度随 N 呈指数级增加 传统的求解方法采用基于回溯算法的策略 当
  • 最简单的8421码计算方法

    很简单 0 9 就是按照二进制来的 0 0000 1 0001 9 1001 超出9以后把10进制情况下的数按照个十百千万的位数拆开 并把每一位按照8421转换后合起来 10 10000 11 10001 19 11001 20 10000
  • 多元线性回归分析spss结果解读_Spss的线性回归做法及结果解读

    上一节我们讲过了eviews做多元回归 但是很多同学做问卷之类的都需要用到spss 所以这节我教一下大家如何用spss做多元回归 并对结果进行解读 再对大家所疑惑的显著水平做一些白话的解释 一 线性回归的操作 将因变量和自变量移入对应的框中
  • C++ primer 之定义行为像指针的类

    提前声明 这是一篇水博 1 使用智能指针实现 include