侯捷c++课程笔记: string类
class with pointer members
由于字符串的长度是不确度的,所以使用数组来存放字符串,不好确定数组大小
因此选择使用char* 动态分配内存的方式来存储
Big three 3个特殊函数
字符串string类的数据成员只有一个char* 指针,通过动态分配内存指向字符串
带有指针的类有三个特殊函数 析构函数 复制构造函数 operator =
不能使用编译器自动生成的operator =和复制构造函数,这些函数是直接的bit by bit 的指针赋值
会造成内存泄漏,即内容还在那里,没有被回收,但没有指针指向这里
同时会形成两个指针指向同一块内存区域,当一个指针delete后,另外一个也会受影响(alias)
复制构造函数和构造函数
首先获取参数的字符长度,由于strlen返回的长度不包括结尾的'\0',所以要分配的内存空间要strlen(cstr)+1
在常规的构造函数中,即使指针参数为空指针,也要分配一个char的内存空间,内容为'\0'
inline
String::String(const char* cstr = 0)
{
if (cstr)
{
m_data = new char[strlen(cstr) + 1];
strcpy(m_data, cstr);
}
else
{
m_data = new char[1];
*m_data = '\0';
}
}
调用strcpy复制,自动复制结尾的'\0'
值得注意的是 类似于String s2=s1
这种,在编译器看来是直接调用复制构造函数,而不是先调用默认构造函数,再执行operator =
inline
String::String(const String& str)
{
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data, str.m_data);
}
析构函数
当string类的实例对象的作用域结束后,os会收回其所占用的内存空间
但string类的数据只有一个指针,这个指针所指向的内容是不会自动回收的,所以要在析构函数中手动delete
inline
String::~String()
{
delete[] m_data;
}
operator =
实现和复制构造函数类似,但是要先清空自身内容,再进行赋值
要判定自我赋值的情况,如果不判断,将直接清空自身的内容,指针成为野指针,会发生undefined behavior
inline
String& String::operator =(const String& str)
{
if (this == &str)
return *this;
delete[] m_data;
m_data = new char[strlen(str.m_data) + 1];
strcpy(m_data, str.m_data);
return *this;
}
stack heap
在函数function body内声明的变量,内存来自于stack
heap是os提供的一块global内存空间,可通过new进行动态分配内存
stack object在作用域结束后被自动清理 而heap object仍然存在
static
在变量声明前加static关键字,即为static object,其在作用域结束后仍然存在,直到整个程序结束
global object也可看作一种static object,作用域是整个程序
new delete
new被编译器转化为三个步骤:
1.调用malloc分配内存
2.static_cast类型转换
3.调用构造函数
delete为两个步骤:
1.调用析构函数
2.调用free释放内存
array new 一定要搭配 array delete
delete 和 delete[] 都会将其所指的内存块全部释放
区别在于delete[]会对数组内的每一个元素调用析构函数 而delete只对第一个元素调用
如果数组元素为带有指针成员的类,使用delete会造成memory leak