class with pointer menbers

string_test.cpp

 1 #include "string.h"
2 #include <iostream>
3
4 using namespace std;
5
6 int main()
7 {
8 String s1("hello");
9 String s2("world");
10
11 String s3(s2);
12 cout << s3 << endl;
13
14 s3 = s1;
15 cout << s3 << endl;
16 cout << s2 << endl;
17 cout << s1 << endl;
18 }

string.h

 1 #ifndef __MYSTRING__
2 #define __MYSTRING__
3
4 class String
5 {
6 public:
7 String(const char* cstr=0);
8 String(const String& str);
9 String& operator=(const String& str);
10 ~String();
11 char* get_c_str() const { return m_data; }
12 private:
13 char* m_data;
14 };
15
16 #include <cstring>
17
18 inline
19 String::String(const char* cstr)
20 {
21 if (cstr) {
22 m_data = new char[strlen(cstr)+1];
23 strcpy(m_data, cstr);
24 }
25 else {
26 m_data = new char[1];
27 *m_data = '\0';
28 }
29 }
30
31 inline
32 String::~String()
33 {
34 delete[] m_data;
35 }
36
37 inline
38 String& String::operator=(const String& str)
39 {
40 if (this == &str)
41 return *this;
42
43 delete[] m_data;
44 m_data = new char[ strlen(str.m_data) + 1 ];
45 strcpy(m_data, str.m_data);
46 return *this;
47 }
48
49 inline
50 String::String(const String& str)
51 {
52 m_data = new char[ strlen(str.m_data) + 1 ];
53 strcpy(m_data, str.m_data);
54 }
55
56 #include <iostream>
57 using namespace std;
58
59 ostream& operator<<(ostream& os, const String& str)
60 {
61 os << str.get_c_str();
62 return os;
63 }
64
65 #endif

注意的点

  • string_test.cpp:11拷贝构造,14拷贝赋值
  • string.h:8拷贝构造(构造函数接受自己),9拷贝赋值,10析构函数
  • 不知道将来要创建的对象多大,所以只放一根指针,再动态创建空间放对象
  • 类中带指针,要关注三个特殊函数(Big Three)
  • 结束符号“\0”判断字符串结束
  • 21判断是否空指针
  • 22:new:,动态分配一块内存
  • 31-35:delete,析构函数,防止内存泄露,变量离开作用域时自动调用
  • 11的get_c_str()是为了配合输出函数

拷贝构造(copy ctor)

  • String a("Hello"); String b("World"); b = a;
  • 如果没有构造拷贝,会发生b和a的指针都指向“Hello”,“World”没有指针指向,导致内存泄露
  • 而且a、b一个改动会影响另一个,别名在编程中是危险的事
  • 这种拷贝方式称为“浅拷贝”,是编译器的默认版本
  • copy ctor 实现“深拷贝”,创建足够的新空间存放蓝本
  • String s2(s1); 与 String s2 = s1; 效果相同

拷贝赋值(copy op =)

  • String s1("hello"); String s2(s1); s2 = s1;
  • 过程:43删除左值--44开辟新空间--45拷贝右值
  • 40-41:检测自我赋值(self assignment),来源端和目的端是否相同
  • 这步的意义不只是提高效率,不这样写会出错
  • 因为43会把原空间删掉,导致45行复制的时候访问空指针

栈(stack)和堆(heap)

  • {Complex c1(1,2);}
  • {Complex* p = new Complex(3);
  • delete p;}
  • stack:存在于某作用域(scope)的一块内存空间,调用函数时,函数本身即形成一个stack用来防止它接受的参数,以及返回地址,离开作用域后,析构函数被自动调用(aoto object)
  • heap:system heap,操作系统提供的一块global内存空间,程序可以动态分配(dynamic allocated)从中获得若干区域,使用完后需手动释放空间
  • {static Complex c1(1,2);}
  • 静态对象,离开作用域后对象仍存在,组用域是整个程序
  • 全局对象,写在任何作用域之外(全局作用域之中),也可看做一种静态对象
  • new:先分配memory,再调用ctor,分解为以下三个函数
  • void* mem = operator new(sizeof(Complex)); // 分配内存,operator new调用malloc(n)
  • p = static_cast<Complex*>(mem); // 转型
  • p->Complex::Complex(1,2); // 构造函数,Complex::Complex(pc,1,2);
  • delete:先调用析构函数,再释放内存
  • String::~String(p); // 把字符串里面动态分配的内存删掉(字符串本身只是指针m_data)
  • operator delete(p); // 内部调用free(p),删掉字符串本身的指针

new到底分配多少内存

  • 调试模式下加上debug header 32byte,正常模式下中间为数据(一根指针4byte),上下为cookies 2*4byte,凑够16的倍数
  • 动态分配所得的array
  • new []:array new
  • delete[]:array delete
  • array new 一定要搭配 array delete
  • String* p = new String[3]; delete[] p; // 唤起3次dtor
  • String* p = new String[3]; delete p; // 唤起1次dtor,另外2个指针指向的动态内存数据无法删除(注意指针是可以删除的)
  • 虽然new complex的时候不会产生此问题,但也要注意搭配使用,养成好习惯

参考:

const在函数前面与后面的区别

https://blog.csdn.net/qq_25800311/article/details/83054129

最新文章

  1. Daily Scrum02 12.16
  2. 文本框只读属性,disabled不能提交
  3. 支持HTML5新标签
  4. Linux基本权限
  5. 一大坨GoogleAPI的学习笔记之一(oAuth2.0)
  6. 浅谈JavaScript性能
  7. Android学习之 WebView使用小结
  8. MVC模式学习笔记
  9. LINQ 的查询_联表、分组、排序
  10. python基础操作_文件读写操作
  11. 利用KVC的方式更方便地获取数组中对象的属性的最值平均值等
  12. LoadRunner性能测试过程中报Error(-17998):Failed to get [param not passed in call] thread TLS entry.
  13. 省市区/国籍 多级联动-jq
  14. jdbc连接sql数据库
  15. bootstrap tooltips在 angularJS中的使用
  16. PowerBi利用Python Script绕过ODBC来导入MongoDB数据
  17. Eclipse导入的User Libarary
  18. Linux/Windows双系统引导修复
  19. [qemu] qemu从源码编译安装
  20. 【POJ3061】Subsequence

热门文章

  1. springboot——发送put、delete请求
  2. 【NX二次开发】根据部件名返回部件tag,UF_PART_ask_part_tag
  3. 【NX二次开发】NX内部函数,查找内部函数的方法
  4. Feign Client 原理和使用
  5. Linux驱动中的EPROBE_DEFER是个啥
  6. 轻松吃透实时时钟芯片DS1302软硬件设计,看完秒懂
  7. ANDROID开发 Fatal signal 11(SIGSEGV) at 0x问题解决方案
  8. Keyboarding(信息学奥赛一本通-T1452)
  9. 31、服务器磁盘、内存、cpu使用率监控
  10. 2018-10-14普及模拟赛」Hash 键值 (hash)