技术在于交流、沟通,转载请注明出处并保持作品的完整性。

概要

一.拷贝构造

二.拷贝赋值

三.重写操作符

四.生命周期


本节主要介绍 Big Three 即析构函数,拷贝构造函数,赋值拷贝函数,前面主要围绕不带指针的class complex本节中主要围绕带指针的String类

前面我说过如果你创建的类不带有指针,那么多半你可以不用写析构函数,但是如果你创建了一个带指针的类,那么你必须重写Big Three

创建一个类

class String
{
public:
String(const char* cstr=);
String(const String& str);
String& operator=(const String& str);
~String();
char* get_c_str() const { return m_data; }
private:
char* m_data; //由于带有指针 ,所以需要重写析构函数,拷贝构造,赋值拷贝
};

一.拷贝构造

如下操作会调用拷贝构造函数

String a{"hello"};

它的实现为

inline
String::String(const char* cstr) //拷贝构造
{
if (cstr) {
m_data = new char[strlen(cstr)+];
strcpy(m_data, cstr);
}
else {
m_data = new char[];
*m_data = '\0';
}
}

这个大家都应该理解


二.拷贝赋值

下面做赋值拷贝操作

String a{"hello"};
String b{"world"};
s1 = s2;

若果我们使用编译器自带的赋值拷贝就会发生下面的现象

这样操作会产生野指针,  因为a和b同时指向 hello  ,没人指向world

同时如果a和b同时指向同一块内存,如果你删掉a的话  b指向的内存也会被删掉,这可不是我们想要的

所以我们必须重写赋值拷贝函数,下面是正确的赋值拷贝函数

inline
String& String::operator=(const String& str) //拷贝赋值
{
if (this == &str) //防止自我赋值 //如果不写这个判断,那么执行带1的时候,就会先杀掉自己,导致错误
return *this; delete[] m_data; //1释放自己内存
m_data = new char[ strlen(str.m_data) + ];//2.创建新的内存
strcpy(m_data, str.m_data); //3.copy
return *this;
}

赋值拷贝的三个步骤: 1.释放自身内存 2.创建新内存 3.copy

注意上面的红色部分


三.重写操作符

因为string类是你新创建的,所有cout不识别你自己创建的类,所以你要重写一个<<

#include <iostream>
using namespace std; ostream& operator<<(ostream& os, const String& str) //如果写成成员函数调用的时候是这样 c1 << cout 是不是很难接受啊
{
os << str.get_c_str();
return os;
}

四.生命周期

下面我来介绍一个内存管理

1.Stack(栈),是存在于某作用域 (scope) 的一一块内存空间 (memory space)。例如当你调用函数,函数本身即 會形成一個 stack 用来放置它所接的参数,以及返回地址

2.Heap, system heap,是指由操作系統提供的 一块 global 內存空間,程序可动态分配 (dynamic allocated) 从某中获得若干区块 (blocks)

例如

String s1{"hello"};//stack
String s2 = new String("world");// 动态分配 heap
static Complex c2(,); //static

stack 栈 的生命周期在作用域结束之际结束.自动清理

heap 堆 的生命周期在他被调用delete之际结束

static 静态对象 生命周期会一直存在带程序结束之际

global 全局对象 其生命在整个程序结束之后 才结束。你也可以把它视为一种 static object,其作用域 是「整个程序」


五.内存管理

先说一下new 和 delete 的调用过程

1. new:先分配 memory, 再調用 ctor

 Complex* pc = new Complex(,);

编译器会把它翻译成

void* mem = operator new( sizeof(Complex) ); //分配內存,其内部调用malloc
pc = static_cast<Complex*>(mem); //转型
pc->Complex::Complex(,); //构造函数 pc->Complex::Complex(1,2);

2. delete:先調用 dtor, 再釋放 mxemory

Complex* pc = new Complex(,);
...
delete pc;

编译器转化为

Complex::~Complex(pc); // 析构函数
operator delete(pc); // 释放內存 其内部调用feee()

下面是说一下动态分配所得的内存块以VC编译器为例

debug版 complex类内涵两个double型成员变量(实部虚部)

每格4字节

是不是感到有些惊讶,在debug版下 我们仅new complex() 到底给我们带来多少的内存呢

头部和尾部(红色部分)的00000041是 cookie 是两个4字节内存  cookie负责标记内存 最后一位的1是代表获得内存     如果最后一位是0回收内存  4*2 = 8bit

灰色部分是VC分期内存是赋予的每块debug内存都会有这块内存 4*8 + 4 = 36bit

绿色部分是我们的conplex       8bit

青色部分是补位部分,因为VC下每一块内存必须是16的倍数

那么我们new一个complex系统应该分配给 (4*2) + 36 + 8 + (4*3 补位) = 64bit

那么非debug版

4*2  + 8 = 16;

下面我们来看一下带指针的string类

debug版

4+(32+4)+(4*2) = 48

非debug版

4+(4*2) + 4 = 16

可见指针占用的内存小一些

总结

1.带有指针的class必须重写Big Three这是一个非常良好的习惯

2.指针更省内存

如有不正确的地方请指正

参照<<侯捷 C++面向对象高级编程>>

C++面向对象高级编程(三)基础篇的更多相关文章

  1. C++面向对象高级编程(四)基础篇

    技术在于交流.沟通,转载请注明出处并保持作品的完整性. 一.Static 二.模板类和模板函数 三.namespace 一.Static 静态成员是“类级别”的,也就是它和类的地位等同,而普通成员是“ ...

  2. C++面向对象高级编程(二)基础篇

    技术在于交流.沟通,转载请注明出处并保持作品的完整性. 概要 知识点1.重载成员函数 知识点2 . return by value, return by reference 知识点3 重载非成员函数 ...

  3. C++面向对象高级编程(一)基础篇

    技术在于交流.沟通,转载请注明出处并保持作品的完整性. 概要: 知识点1 构造函数与析构函数 知识点2 参数与返回值 知识点3 const 知识点4 函数重载(要与重写区分开) 知识点5 友元 先以C ...

  4. C++面向对象高级编程(八)模板

    技术在于交流.沟通,转载请注明出处并保持作品的完整性. 这节课主要讲模板的使用,之前我们谈到过函数模板与类模板 (C++面向对象高级编程(四)基础篇)这里不再说明 1.成员模板 成员模板:参数为tem ...

  5. 夯实Java基础系列1:Java面向对象三大特性(基础篇)

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 [https://github.com/h2pl/Java-Tutorial](https: ...

  6. C++面向对象高级编程(九)Reference与重载operator new和operator delete

    摘要: 技术在于交流.沟通,转载请注明出处并保持作品的完整性. 一 Reference 引用:之前提及过,他的主要作用就是取别名,与指针很相似,实现也是基于指针. 1.引用必须有初值,且不能引用nul ...

  7. C++面向对象高级编程(五)类与类之间的关系

    技术在于交流.沟通,转载请注明出处并保持作品的完整性. 本节主要介绍一下类与类之间的关系,也就是面向对象编程先介绍两个术语 Object Oriented Programming   OOP面向对象编 ...

  8. C++面向对象高级编程(七)point-like classes和function-like classes

    技术在于交流.沟通,转载请注明出处并保持作品的完整性. 1.pointer-like class 类设计成指针那样,可以当做指针来用,指针有两个常用操作符(*和->),所以我们必须重载这两个操作 ...

  9. C++面向对象高级编程(六)转换函数与non-explicit one argument ctor

    技术在于交流.沟通,转载请注明出处并保持作品的完整性. 1.conversion function 转换函数 //1.转换函数 //conversion function //只要你认为合理 你可以任 ...

随机推荐

  1. 【GZAdmin】开源BS demo快速搭建

    下载搭建项目:链接:https://pan.baidu.com/s/1jHZ3Kkm 密码:5k4q 项目源码: GZAdmin_API:https://github.com/GarsonZhang/ ...

  2. ThinkPHP项目 公共方法存放位置

    ThinkPHP项目公共方法写在   根目录-> app-> common 里面 ThinkPHP模板公共方法卸载   根目录->app->模块名称->common  里 ...

  3. 在python3下使用OpenCV 抓取摄像头图像并实时显示3色直方图

    以下代码为在Python3环境下利用OpenCV 抓取摄像头的实时图像, 通过OpenCV的 calHist函数计算直方图, 并显示在3个不同窗口中. import cv2 import numpy ...

  4. FileSystemWatcher监听文件是否有被修改

    作用:监听文件系统更改通知,并在目录或目录中的文件更改时引发事件. 需求:监听特定文件是否修改,然后做出相应的操作. 方法: ①利用一个线程,一直去查找该指定的文件是否有被修改,如果修改则操作特定步骤 ...

  5. 从零开始玩转JMX(一)——简介和Standard MBean

    JMX的全称为Java Management Extensions. 顾名思义,是管理Java的一种扩展.这种机制可以方便的管理.监控正在运行中的Java程序.常用于管理线程,内存,日志Level,服 ...

  6. ELK出现unassigned_shards查看及删除

    问题 用3台服务器搭建了ELK系统,有一天出现有几个索引一直无法同步,重启了elasticsearch也不行 如下图:elk-cluster一直处于red状态 解决方法 一,查看elasticsear ...

  7. Mac OS build caffe2 Error:This file was generated by an older version of protoc which is

    问题所在 我们可以发现这个错误跟protobuf的版本有关,因此我们可以执行script/diagnose_protobuf.py 我们可以看到,pip install protobuf 和 brew ...

  8. 随机数的生成 - rand(), srand()

    2017-08-20  17:43:29 writer:pprp 我们采用随机数可以对我们的算法进行大数据检验 /* name : 简单的随机数生成算法 writer : pprp declare : ...

  9. caohaha's stuff

    2017-08-20 11:12:29 writer:pprpCCPC预选赛水平太菜了,去不了了 这个是一个找规律的题目,题意一开始也很难理解 题意描述: 给你一个数,比如说1,在一个坐标系中你需要用 ...

  10. 那些年java MD5加密字符编码的坑

    相信做过MD5加密的童鞋都遇到过字符编码的坑,一般加密出来的结果和其他人不一样都是字符编码不一致导致的,比如类文件的字符编码.浏览器的字符编码等和对方不一致,所以就需要转码统一字符. 以下是笔者转码过 ...