Primer Plus 类和动态内存分配

StringBad的问题

特殊成员函数

当按值传递和返回对象时,都将调用复制构造函数

如果类中包含用来计数当前有多少个对象的静态变量,应该提供一个显式的复制构造函数用来处理静态变量

因为编译器提供的复制构造函数不改变静态变量的值,所以如果析构函数里减小了静态变量

而程序里又有哪里调用了默认复制构造函数,将造成计数偏小

因为隐式复制构造函数是浅拷贝,还可能不小心delete浅拷贝的指针指向的地方,导致原本的数据没了

解决方法是提供一个能深拷贝的显式复制构造函数

赋值运算符

1
2
3
4
5
6
7
// 假设有=的重载StringBad & StringBad::operator=(const StringBad &);
StringBad a("hello");

String b;
b = a; // 调用了重载的=

String c = a; // 初始化对象时,可能调用的是复制构造函数,也可能是重载的=

如果重载的=内部使用浅拷贝,指针就也可能出问题,一个对象先析构,另一个对象后析构,同一个地址会被释放两次

解决方法也是深拷贝,区别是要注意处理自己赋给自己的情况,以及要把原本要覆盖的的内容释放掉(如果有用new申请的)

对于自己的string类,默认构造函数可能这样写,因为析构函数里是delete[],要配套

1
2
3
4
5
6
String::String() {
len = 0;
// 不写成 str = new char;
str = new char[1];
str[0] = '\0';
}

比较函数写成友元函数的好处是运算符左侧是c_str时,编译器会转换

[]是二元运算符,对于a[x],a是第一个操作数,b是第二个

重载operator[]时,要提供一个仅供const String对象使用的版本

const变量只能初始化不能赋值,所以涉及const变量的构造函数必须这样写

1
2
3
4
Queue::Queue(int qs) : qsize(qs) {
front = rear = nullptr; // 这几个变量也可以像qsize那样写,但qsize必须那样写
items = 0;
}

初始化列表语法是直接调复制构造函数,相比在构造函数体里用赋值语句(左操作数先调用默认构造函数,再调用重载的=来将右操作数赋给左操作数)节省步骤