侯捷C++个人学习笔记Part1以String函数为例(有指针)

String函数为例的C++学习笔记

拷贝构造,拷贝赋值,析构函数

这三个函数被称为BIG Three
string.h的防卫式声明
一般根据主函数来确定需要编写的函数
在这里插入图片描述
s3(s1)拷贝构造和s3=s2拷贝赋值。由此可知我们需要一个拷贝的动作和一个操作符<<的重载

如果class中带指针一定要自己写构造函数
在这里插入图片描述
一般而言都会先创建一个指针,只有当需要传入字符串的时候才会申请空间存放字符串。在本函数中m_data充当这个指针。
char指针指向字符串的解释
对于语句 char *a=“hello”;
对于这个声明方式,会造成的误解是:声明了一个字符指针(它会指向一个位置),将“字符串”赋值给 指针表达式"*a"所指向的地址。
正解是:声明了一个字符指针后,并用字符串常量的第一个字符的地址赋值给指针变量a。
即正确顺序是:

1.分配内存给字符指针;
2.分配内存给字符串;
3.将字符串首地址赋值给字符指针;

被圈起来的函数属于自定义函数声明。第一个函数是构造函数,第二个构造函数就是拷贝构造,第三个是一个操作符重载,用于拷贝赋值。只要类带着指针一定要写拷贝构造和拷贝赋值函数
第四个函数是析构函数,以此类做出来的对象当它死亡时,析构函数就会被调用

析构函数和构造函数
在这里插入图片描述
strlen函数会从首地址读到结束地址并返回个数
构造函数
if(cstr)表示判断传入的指针是否为0,如果为0则将传到else。if(cstr)等同于if(cstr!=0)
strlen(cstr)+1是为了存放结束符号

对于char[]=“chinese”,在计算数组长度时包不包括结束标志’\0’,那么对于char[]={‘c’,‘a’,‘t’}这种数组呢?
所有计算字符串的长度都不包括结束标志’\0’,第2种情况同样。
对于前一种情况,如果用strcpy将一个数组复制到另一个数组时,会否将结束标志也复制过去呢?

如果是,那么在输出复制后的数组时遇到该结束标志是否会终止?为什么?
会终止,因为有结束符。
如果不终止,那么是输出0还是空格呢?为什么?
会终止

析构函数是为了清理动态分配的内存
默认拷贝(浅拷贝)的坏处
在这里插入图片描述
会造成两个object指向同一块空间。
拷贝构造函数(深拷贝)
在这里插入图片描述
拷贝赋值函数
需要先把左边清空然后分配和右边一样大的空间容纳右边的内容
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

s2是调用操作符=的对象所以它是this,s1是传入的str
如果不写自我赋值结果还可能会出错
在这里插入图片描述
在这里插入图片描述
output函数不可以是成员函数只能是全局函数,如果它是成员函数那么cout方向会相反即变成s1<<cout;
成员函数的第一个参数是默认的this

堆,栈与内存管理

在这里插入图片描述
Heap由关键字new动态分配获得,当你获得Heap时你有责任去delete它
stack objects的生命期在这里插入图片描述
static local objects的生命期
在这里插入图片描述
global objects的生命期
在这里插入图片描述
全局对象是存在于任何大括号之外的
heap objects的生命期
在这里插入图片描述
关键字new
在这里插入图片描述
new关键字来创建对象时,先会得到一块空间然后调用构造函数
绝大部分new会被分解成上图三个动作,operator new是一个函数的名称(由C++提供,malloc是C里面调用内存的函数)
第三步中pc在构造函数中this
关键字delete
在这里插入图片描述
先调用析构函数清除自己动态分配的内存,再释放字符串本身(指针)内存
动态分配所得的内存块,在VC下
在这里插入图片描述
以Complex为例
Complex对象有两个double申请的空间占用8个byte即8个字节,上图每一格是4个字节上面会多得到32个字节,下面会多得到4个字节(灰色的部分即多得的部分),砖红色是cookie,因为VC下分配的空间一定是16的倍数所以最靠近52字节的16的倍数就是64。图中的pad就是填补物。

第二个图是不会进入调试模式(debugger module),不会加上debugger header(上32,下4)但一定要加上 上下cookie。

上下cookie最主要的工作是要记录给你的区块大小
第一个图中的上cookie是41但本来应该是40即4*16,以16进制的方式存储。40借用最后一位即0或1来表现这一块是给出去还是收回来,因为是操作系统给出来了所以是41。为什么可以借最后一位来使用,因为是16的倍数所以一般最后一位都是0。

以String为例
字符串本身只内含一个指针,所以指针的大小是4byte

动态分配的array
array new要搭配array delete
在这里插入图片描述
在调试模式下3个complex上要加32bytes,下要加4byte,上下cookie,最后加的4bytes是因为是一个数组用一个整数来记录有3的东西
h代表16进制
在这里插入图片描述
有无中括号都不影响删除,因为上下cookie记录了内存块大小

发生内存泄漏是因为如果不写中括号编译器就不知道是数组,只会调用一次析构函数,析构函数执行完毕后才会执行删除母体。内存泄漏发生在2和3指向的空间不是母体。如果发生在指针函数里是否是delete []都可以。

复习String的实现过程
String使用的是C风格的字符串即char指针指向首字符

   String& operator=(const String& str);    
   //执行的结果放到什么地方去,如果放的结果不是local object那么就可以选择传reference
char* get_c_str() const { return m_data; }
//此函数内没有改变任何数据因此可以加上const,如果需要加上const需要加上函数名称后面

构造函数和析构函数

//构造函数
inline
String::String(const char* cstr)
{
   if (cstr) { //cstr存在?
      m_data = new char[strlen(cstr)+1];//如果cstr指针不是0,new的形式创建足够大的空间,+1是加上字符串的结束符号
      strcpy(m_data, cstr);
   }
   else {   //为指定初值,cstr为0
      m_data = new char[1];
      *m_data = '\0';//结束符号
   }
}

//析构函数
inline
String::~String()
{
   delete[] m_data;//我们分配了空间(不管哪一种情况)
}

拷贝构造函数

inline
String::String(const String& str)
{
   m_data = new char[ strlen(str.m_data) + 1 ];//足够大的空间,一定要+1
   strcpy(m_data, str.m_data);
}

拷贝赋值函数

inline
String& String::operator=(const String& str)//这里的&叫reference,放在typename后面
{
   if (this == &str)//这里的&叫做取地址,放在object前面
      return *this;  //必须先查询是否是自己赋值自己即来源端是否和目的端相同
      //如果没有这个检查那么会先清除自己导致错误

   delete[] m_data;  //目的端要清除自己
   m_data = new char[ strlen(str.m_data) + 1 ];//目的端要分配足够大的空间
   strcpy(m_data, str.m_data);
   return *this;//如果设置成void 某种情况下可以某种情况下不行。
   //如果是连串的赋值例如s1=s2=s3=“hello”,那返回类型就不能是void。
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值