Big3:三个特殊函数
1. 拷贝构造函数:第一次出现 s3(s1)
2. 拷贝赋值函数 s3=s2
3. 析构函数
编译器自带,够用的话不需要自己写,否则需要自己写
如果类中包含指针,必须要有拷贝构造和拷贝赋值,否则只对指针进行拷贝,就是所谓的浅拷贝,会使两个指针指向同一内容(alias别名),造成内存泄漏
拷贝构造函数:
inline
String::String(const String& str)
{
m_data = new char[strlen(str.m_data) + 1]; //同一类的对象之间互为friend
//可直接访问private data
strcpy(m_data,str.m_data);
}
拷贝赋值函数:(三步走)
inline
String& String::operator=(const String& str)
{
/*1. 检测自我赋值self assignment*/
if(this == &str)
return *this;
/*2. 将原来的内存清空,分配跟新的值一样大的内存空间*/
delete[] m_data;
m_data = new char[strlen(str.m_data) + 1];
/*3. 进行拷贝操作*/
strcpy(m_data,str.m_data);
return *this;
}
检测自我赋值:
1.效率高:如果是自我赋值可以直接返回自身,不需要进行后续操作;
2.正确性:否则在执行时可能会出错
堆、栈与内存管理
栈
存在于作用域中的一块内存空间,离开作用域自动消失(auto object自动调用析构函数,自动清理)
静态对象static object:生命在作用域结束后依然存在直到整个程序结束
全局对象global object:可视为static object,但其作用域为整个程序
堆
由操作系统提供的一块global内存空间,程序可动态分配,需要手动delete指针,否则出现内存泄漏(指针没了,但指针指向的内存还在)
new
先分配内存,再调用构造函数
-分配内存:operator new函数,内部调用malloc
-转型:改变指针类型
-通过指针调用构造函数
delete
先调用析构函数,再释放内存
-调用析构函数:杀掉字符串内动态分配的内存
-释放内存:operator delete:杀掉字符串本身,内部调用free
内存块剖析
动态分配所得的内存块
需要是16的倍数,pad
cookie记录内存大小
动态分配所得的array
array new一定要搭配array delete
因为有cookie存在,delete中不写[]也不会造成删除字符串本身时的内存泄露
但这样只会调用一次string析构函数
复习课
big3:
1. 拷贝构造:蓝本,传引用
2. 拷贝赋值:来源端→目的端,返回引用
3. 析构函数
函数全部写成inline也没关系
引用和取地址操作,符号相同但操作不同