文章目录
1、C++指针大小
CPU位数 = CPU中寄存器的位数 = CPU能够一次并行处理的数据宽度 = 数据总线宽度
操作系统位数 = 其所依赖的指令集位数 <= CPU位数
CPU寻址能力 = 2s (s为地址总线宽度) <= CPU位数
指针大小是由当前CPU运行模式的寻址位数所决定的,位数是指CPU中通用寄存器的数据宽度是64位,即一个地址所占的二进制位数是64,即8个字节。
2、构造函数的执行算法
- 在派⽣类构造函数中,所有的虚基类及上⼀层基类的构造函数调⽤;
- 对象的 vptr 被初始化;
- 如果有成员初始化列表,将在构造函数体内扩展开来,这必须在 vptr 被设定之后才做;
- 执⾏程序员所提供的代码;
3、何时需要成员初始化列表
- 当初始化⼀个引⽤成员变量时;
- 初始化⼀个 const 成员变量时;
- 当调⽤⼀个基类的构造函数,而构造函数拥有⼀组参数时;
- 当调⽤⼀个成员类的构造函数,而他拥有⼀组参数;
过程: 编译器会⼀⼀操作初始化列表,以适当顺序在构造函数之内安插初始化操作,并且在任何显示⽤户代码前。 list中的项⽬顺序是由类中的成员声明顺序决定的,不是初始化列表中的排列顺序决定的。
4、构造、析构函数不能抛异常
构造函数: C++ 只会析构已经完成的对象,对象只有在其构造函数执⾏完毕才算是完全构造妥当。在构造函数中发⽣异常,控制权转出构造函数之外。因此,在对象 b 的构造函数中发⽣异常,对象b的析构函数不会被调⽤。因此会造成内存泄漏。
析构函数:
1)如果析构函数抛出异常,则异常点之后的程序不会执行,如果析构函数在异常点之后执行了某些必要的动作比如释放某些资源,则这些动作不会执行,会造成诸如资源泄漏的问题。
2)析构函数是异常处理的一部分。通常异常发生时,c++的机制会调用已经构造对象的析构函数来释放资源,此时若析构函数本身也抛出异常,则前一个异常尚未处理,又有新的异常,会造成程序崩溃的问题。
5、类如何实现只能静态分配和只能动态分配
1 只静态分配(栈):
把 new、 delete 运算符重载为 private 属性。
(只有使用new运算符,对象才会被建立在堆上)
2 只动态分配(堆):
把构造、析构函数设为 protected 属性,再用子类来动态创建。
(定义为私有的话就不能被继承了,定义为保护则只能在子类和本类内部调用)
(如果类的析构函数在类外部无法访问,则编译器拒绝在栈空间上为类对象分配内存)
6、什么时候用static?
需要一个数据对象为整个类而非某个对象服务,同时又力求不破坏类的封装性,即要求此成员隐藏在类的内部,对外不可见。
1 static成员变量
只与类关联,不与类的对象关联。定义时要分配空间,类内声明,类外定义与初始化。初始化时不需要标示为static;可以被非static成员函数任意访问。
2 static成员函数
没有this指针,无法访问类对象的非static成员变量和非static成员函数;不能被声明为const、虚函数和volatile;可以被非static成员函数任意访问。
3 static全局变量
静态存储区,隐藏功能,作用域只在本文件中,只初始化一次。
4 static局部变量
静态存储区,作用域还是局部,但是程序运行期一直存在。
5 static普通函数
只能在本文件中使用。
7、几种类型的new
new和malloc申请的都是虚拟内存,在首次访问这个内存时,会产生缺页中断,内核在这个时候会给进程分配实际的物理内存。
1. plain new
普通的new,内存分配失败后会抛出异常而不是返回NULL。
2. nothrow new
在内存分配失败后不抛出异常,而是返回NULL
3. placement new
允许在一块已经分配成功的内存上重新构造对象或对象数组。
它不分配内存,做的唯一一件事就是调用对象的构造函数。
使用placement new需要注意两点:
- palcement new的主要用途就是反复使用一块较大的动态分配的内存来构造不同类型的对象或者他们的数组
- placement new构造起来的对象数组,要显式的调用他们的析构函数来销毁(析构函数并不释放对象的内存),千万不要使用delete,这是因为placement new构造起来的对象或数组大小并不一定等于原来分配的内存大小,使用delete会造成内存泄漏或者之后释放内存时出现运行时错误。
8、push_back和emplace_back
emplace_back函数的作用是减少对象拷贝和构造次数。
push_back():
先向容器尾部添加一个右值元素(临时对象),然后调用构造函数构造出这个临时对象,最后调用移动构造函数将这个临时对象放入容器中并释放这个临时对象。
- 注:最后调用的不是拷贝构造函数,而是移动构造函数。因为需要释放临时对象,所以通过std::move进行移动构造,可以避免不必要的拷贝操作。
emplace_back():
在容器尾部添加一个元素,调用构造函数原地构造,不需要触发拷贝构造和移动构造。因此比push_back()更加高效。