Loading

侯捷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

posted @ 2021-09-04 17:38  traver  阅读(75)  评论(0编辑  收藏  举报