条款4:确保变量之前初始化过
变量的初始化和变量的赋值首先就是两个概念,初始化是为变量开辟一定的空间,但是赋值是为变量赋初值,和初始化有本质的不同。
对于内置类型的成员变量,必须手动完成对变量的初始化。例如
int x = 0;
const char * text = "A C-Style String" ;
double b;
std::cin >> b;
但是对于非内置类型以外的其他变量来说,初始化的责任落在了构造函数里面。确保构造函数完成所有的变量的初始化的工作。
但是对于一个构造函数来讲,如果使用以下的方法进行赋值是可以获得需要的初始值,但这不是最佳的初始化方案。
class example{
public:
example(int num,string str1,string str2)
{
this->num = num; //这些其实都是赋值不是初始化
this->str1 = str1;
this->str2 = str2;
}
private:
int num;
string str1;
string str2;
};
c++的规定就是先调用malloc函数给变量开辟空间初始化,之后再调用构造函数,上述的变量其实都调用了默认构造函数。
但是int类型并没有构造函数,所以在赋值之前可能就没有一个固定的初值。如果要是多线程的话或许会造成一些问题。
推荐使用的是成员初值列的初始化方式。
example::example(int num,string str1,string str2):num(num),str1(str1),str2(str2){};
这种方法再初始化的时候就直接给赋予相应的初值,所以在执行构造函数之前就会有相应的初值。调用的是拷贝构造,如果是禁用拷贝构造的对象就是用引用类型传递进来。
这种方法带有一定的次序性,按照次序依次初始化变量。
对于定义在不同的编译单元里面的non-local static对象的初始化次序
所谓的static对象,寿命从被构造出来到程序结束为止,在编译阶段就已经初始化完毕。
static变量有两种一种是 non-local static 指的是全局的一些变量 namespace 作用域,或者是在class类里面。
另一种是local static变量,这个变量是声明在函数里面的变量,作用域是函数或者文件内部。
c++在初始化no-local static变量的时候是不分前后顺序的,所以在一个编译单位内部的static变量在调用其他的static变量的时候肯定会出现问题。
所以在使用的时候采用local static代替no -local static变量
使用方式如下
class FileSystem{
public:
//...
std::size_t numDisks() const;
FileSystem & tfs{
static FileSystem fs;
return fs;
}
};
class Directory{...};
Directory::Directory(params)
{
...
std::size_t disks = tfs().numDisks(); //使用tfs等函数获取static变量的值
}
//...
extern FileSystem tfs;
条款5:了解c++默认的一些函数使用情况
空类empty class(空类)不再是个empty class,在编译器编译之后就会为一个空类自动生成一个copy构造函数,一个copy assignment操作符和一个析构函数。这些所有的函数都是public 而且inline
构造函数,析构函数,拷贝函数这些函数都是只有被调用的时候才会被编译器创建出来。
default构造函数和析构函数的作用是什么?
为编译器提供一个地方来存放相应的代码,这些代码是调用base class 和non - static成员变量和析构函数,编译器产生的析构函数是non-virtual的。
如果你创建了一个含参数的构造函数,编译器就不会为你在生成默认构造函数了。
调用拷贝构造函数的时候如果是类的话就会调用相应的类,如果是int等基本类型的话就会将其中的内容拷贝到新的类的变量里面。
c++不允许引用改指不同的变量,所以就无法copy assignment进行直接改变引用。但是可以通过改变引用的对象内容间接地改变引用。
但是对于内涵引用和const类型变量的类就需要自己声明copy assignment函数。
条款6:拒绝使用编译器自动生成函数的操作
首先有些类不需要被拷贝或者使用 = copy assignment操作符
首先就是把拷贝构造函数放在private里面,但是这样就会在编译的时候获得一个链接错误。第二个就是继承private uncopyable对象。
条款7:为多态基类声明virtual析构函数
当在执行多态的析构的时候,上转型变量不会调用derived class的析构函数,解决方法就是在派生类里面声明virtual析构函数,这样就会调用相应的子类的析构函数。否则就会发生之调用了基类的析构函数,但是子类多出来的部分也没有被释放,就会造成“局部销毁”的现象产生。
一般来说一个有virtual类型的函数的class一般需要相应virtual析构函数,但是如果一个不包含virtual函数的类却给了virtual的析构函数往往会造成麻烦,这个麻烦就是由于虚函数生成的时候,编译器会给类里面创建一个虚表,这个虚表其实就是一个指针,这个指针指向的是该对象实际需要的那个函数。所以就会占据一定的空间,移植性就降低了。
条款8:别让异常逃离析构函数
析构函数一般不允许抛出异常否则可能会产生不明确行为或者就是异常终止程序。所以需要使用管理类去管理一个类的析构等操作,在析构函数里面需要使用try catch函数将异常捕获,或者就是abort()