关于构造函数,拷贝构造函数,拷贝赋值函数,移动构造函数

c++11移动构造函数

移动构造函数作用

拷贝构造函数和赋值函数

赋值构造函数;
1.拷贝构造函数是一个对象初始化一块内存区域,这块内存就是新对象的内存区,而赋值函数是对于一个已经被初始化的对象来进行赋值操作。
2.一般来说在数据成员包含指针对象的时候,需要考虑两种不同的处理需求:一种是复制指针对象,另一种是引用指针对象。拷贝构造函数大多数情况下是复制,而赋值函数是引用对象。
3.实现不一样。拷贝构造函数首先是一个构造函数,它调用时候是通过参数的对象初始化产生一个对象。赋值函数则是把一个新的对象赋值给一个原有的对象,所以如果原来的对象中有内存分配要先把内存释放掉,而且还要检察一下两个对象是不是同一个对象,如果是,不做任何操作,直接返回。
总结:

			对象不存在,且没用别的对象来初始化,就是调用了构造函数;
			对象不存在,且用别的对象来初始化,就是拷贝构造函数(上面说了三种用它的情况!
			对象存在,用别的对象来给它赋值,就是赋值函数。

赋值函数重载

赋值函数重载

struct C {
C() { std::cout << "1"; }
C(const C& other) { std::cout << "2"; }
C& operator=(const C& other) { std::cout << "3"; return *this;}
};

C fun(){
    return C();
}

int main() {
C c1;
C c2 = c1;
C c3(c1);
C c4 = fun();
return 0;
}

vector为什么以1.5-2倍扩容

链接

define typedefine const inline的区别

define 和 typedefine
原理:#define 作为预处理指令,在编译预处理时进行替换操作,不作正确性检查,只有在编译已被展开的源程序时才会发现可能的错误并报错。typedef 是关键字,在编译时处理,有类型检查功能,用来给一个已经存在的类型一个别名,但不能在一个函数定义里面使用 typedef 。
功能:typedef 用来定义类型的别名,方便使用。#define 不仅可以为类型取别名,还可以定义常量、变量、编译开关等。
作用域:#define 没有作用域的限制,只要是之前预定义过的宏,在以后的程序中都可以使用,而 typedef 有自己的作用域。
指针的操作:typedef 和 #define 在处理指针时不完全一样

define 和 const
编译阶段:define 是在编译预处理阶段进行替换,const 是在编译阶段确定其值。
安全性:define 定义的宏常量没有数据类型,只是进行简单的替换,不会进行类型安全的检查;const 定义的常量是有类型的,是要进行判断的,可以避免一些低级的错误。
内存占用:define 定义的宏常量,在程序中使用多少次就会进行多少次替换,内存中有多个备份,占用的是代码段的空间;const 定义的常量占用静态存储区的空间,程序运行过程中只有一份。
调试:define 定义的宏常量不能调试,因为在预编译阶段就已经进行替换了;const 定义的常量可以进行调试。
const 的优点:有数据类型,在定义式可进行安全性检查。可调试。占用较少的空间。

define 和 inline
内联函数是在编译时展开,而宏在编译预处理时展开;在编译的时候,内联函数直接被嵌入到目标代码中去,而宏只是一个简单的文本替换。
内联函数是真正的函数,和普通函数调用的方法一样,在调用点处直接展开,避免了函数的参数压栈操作,减少了调用的开销。而宏定义编写较为复杂,常需要增加一些括号来避免歧义。
宏定义只进行文本替换,不会对参数的类型、语句能否正常编译等进行检查。而内联函数是真正的函数,会对参数的类型、函数体内的语句编写是否正确等进行检查。
链接

线程安全和可重入性

线程安全: 如果一个函数在同一时刻可以被多个线程安全地调用,就称该函数是线程安全的。线程安全函数解决多个线程调用函数时访问共享资源的冲突问题。
可重入:函数可以由多于一个线程并发使用,而不必担心数据错误。可重入函数可以在任意时刻被中断,稍后再继续运行,其结果不会改变。可重入性解决函数运行结果的确定性和可重复性。

可重入函数编写规范为:
1、不在函数内部使用静态或全局数据
2、不返回静态或全局数据,所有数据都由函数的调用者提供。
3、使用本地数据,或者通过制作全局数据的本地拷贝来保护全局数据。
4、如果必须访问全局变量,利用互斥机制来保护全局变量。
5、不调用不可重入函数。

两者之间的关系:
1、一个函数对于多个线程是可重入的,则这个函数是线程安全的。
2、一个函数是线程安全的,但并不一定是可重入的。【使用互斥锁实现的线程安全】
3、可重入性要强于线程安全性。
链接

top free vmstat命令

top
请添加图片描述

  • 系统当前时间 、系统到目前为止已运行的时间、当前登录系统的用户数量、系统负载(任务队列的平均长度)
  • “所有启动的进程数”、“正在运行的进程数”、“挂起的进程数”、“停止的进程数”、“僵尸进程数”
  • “用户空间占用CPU百分比”、“内核空间占用CPU百分比”、“用户空间内改变过优先级的进程占用CPU百分比”、“空闲CPU百分比”、“等待输入输出CPU时间百分比”、“CPU服务于硬件中断所耗费的时间总额”、“CPU服务软中断所耗费的时间总额”、“Steal Time”
  • 物理内存总量”、“已使用的物理内存”、“空闲物理内存”、“内核缓存内存量”
  • “交换区总量”、“已使用交互区总量”、“空闲交换区总量”、“缓冲的交换区总量”
  • “进程ID”、“进程所有者”、“优先级”、“nice值,负值表示高优先级,正值表示低优先级”、“进程使用的虚拟内存总量”、“进程使用的、未被换出的物理内存大小”、“共享内存大小”、“进程状态”、“上次更新到现在的CPU时间占用百分比”、“进程使用的物理内存百分比”、“进程使用CPU总时间”、“命令名、命令行”

free
请添加图片描述物理内存和交换空间的总量,使用量以及当前空闲量及缓存空间大小,可用空间等。

vmstat
请添加图片描述
等待执行的任务数 等待IO的进程数 正在使用的虚拟内存大小 空闲内存大小 已用的buff和cache的大小 每秒从内存写到交换区的大小 每秒从交换区写到内存的大小 每秒读取的块数 每秒写入的块数 每秒中断数 每秒上下文切换数 用户进程消耗CPU时间 系统进程消耗CPU时间 空闲时间 等待IO时间。

进程、线程上下文切换

进程上下文切换:虚拟地址空间,0-4G地址空间的内容,堆栈,全局变量等,还包括内核空间的内核堆栈,寄存器等。
线程上下文切换:相同进程和不同进程,相同进程,线程私有的寄存器和栈帧等内容。
链接

线程池线程数选择问题

cpu密集型/io密集型
阻抗公式
链接

智能指针实现

链接

Linux文件软连接和硬链接

硬链接只有一个inode,多个文件名指向了同一个inode节点,只要文件的索引节点还存在一个及以上的链接,只删除其中一个链接并不影响索引节点本身和其他链接,只有当最后一个链接被删除时,此时若有新数据需要存储到磁盘上,被删除文件的数据块以及对应的链接才被释放,空间被新数据暂时占用。
软连接是一个单独的文件,拥有属于自身的inode,文件内容为源文件的路径名的指向,通过这个方式可以快速定位到软连接所指向的源文件实体。删除软连接不影响指向的文件,但是如果指向的文件被删除,则软连接失效。

Linux进程与线程底层,task_struct

链接
链接

协程

与进程、线程的概念不同,协程类似于线程中一个特殊的函数,可以随时被挂起,可以随时在挂起处重新恢复运行。
一个进程可以有多个线程,一个线程内可以有多个协程,类似于线程执行的任务中有多个函数,但是这些协程之间的串行的,当一个协程执行时,线程内的其他协程必须被挂起。
多核CPU条件下,多个进程,多个线程可以并行执行,但是协程之间必须是严格串行的,无法利用CPU多核能力。
协程之间也存在上下文切换,但是相比进程与线程来说是轻量级的,只有寄存器内容需要切换,并且不需要进行内核态与用户态之间的切换。
在这里插入图片描述
链接

内存对齐

内存对齐的原因:
1.平台原因:不是所有的硬件平台都能访问任意地址上的任意数据的。某些硬件平台只能在某些地址出取某些特定类型的数据,否则会抛出异常。
2.性能原因:数据结构应该尽可能在自然边界上对齐,如果访问未对齐的数据,处理器可能需要作两次访问取出数据,而内存对齐只需要一次访问就可以取出数据,提高了效率。
内存对齐规则:如果设置了默认对齐长度i,类中最大成员对齐长度为j,则类中的有效对齐长度为min(i,j),某个成员的对齐字节数定义:如果该成员是c++自带类型如int、char、double等,那么其对齐字节数=该类型在内存中所占的字节数;如果该成员是自定义类型如某个class或者struct,那个它的对齐字节数 = 该类型内最大的成员对齐字节数)
结构体的第一个成员变量的偏移值为0,此后每个结构体成员相对于结构体首地址的偏移量都是该成员大小与有效对齐长度最小的那个值的整数倍,如有需要编译器会在成员之间加上填充字节。
结构体的总大小为有效对齐长度的整数倍,如有需要编译器会在最后一个成员后加上填充字节。
链接
链接

virtual 和 override

基类成员函数没有virtual关键字时,如果子类有同名函数,则进行覆盖,使用基类指针调用时使用的是基类的函数,使用子类指针调用时使用的时子类的函数。
基类成员函数加上virtual关键字时就可以实现重写,使用基类指针或引用指向子类对象,调用时都会使用当前子类的成员函数。
成员函数加上override时,强制要求同名函数是虚函数,否则编译报错。
子类成员函数的virtual关键字可加可不加,建议加override不加virtual。

Linux内部命令与外部命令

内部命令是嵌入在shell中的,在系统启动时就调入内存,是常驻内存的,效率比较高。
外部命令是在执行时才从硬盘调入内存的。

内部命令是shell程序的一部分,其包含的是一些比较简单的linux系统命令,这些系统命令有shell自身识别并在shell内部运行,通常linux系统加载时shell就被加载并常驻在系统内存中,内部命令写在bashy源码中,其运行速度比外部命令快,因为解析并运行内部命令时shell不需要创建新的子进程,如cd,exit,history

外部命令是linux系统中的实用程序部分,因为实用程序的功能都比较强大,因此程序量相对较大,系统加载时并不会一起加载到内存中,只有在调用时才会从硬盘写入到内存中,外部命令实体不在shell中,但是其命令执行过程是有shell控制的,shell程序管理外部命令执行的路经查找,加载存放,并控制命令的执行,外部命令通常放在/bin,user/bin,/sbin目录中,如ls,vi,roscore,路径可以通过echo $PATH或which命令查看

内部命令或外部命令可通过type命令判断

链接

Linux调用read的过程(文件系统详解)

链接

类是怎么找到成员函数的

成员函数本质上可以看做是全局函数,不过第一个参数隐式固定为this指针,也就是需要通过实例化得到对象去调用。

“Note:定义在类内部的函数是隐式的inline函数(参见6.5.2节,第214页)。” —— 《C++ Primer》 中文第五版 P230
“成员函数通过一个名为this的额外隐式参数来访问调用它的那个对象。” —— 《C++ Primer》 中文第五版 P231

mmap映射原理

链接

编译原理

预处理
将源代码文件与包含的头文件通过预编译器编译生成.i文件,包括宏定义展开,头文件包含,处理预编译指令,去除注释等。

编译
通过词法和语法分析,将预处理得到的输出文件编译生成.s汇编文件,主要包括编译和优化处理两个过程,优化中间代码和目标代码。
对于前一种优化,主要的工作是删除公共表达式、循环优化(代码外提、强度削弱、变换循环控制条件、已知量的合并等)、复写传播,以及无用赋值的删除,等等。
后一种类型的优化同机器的硬件结构密切相关,最主要的是考虑是如何充分利用机器的各个硬件寄存器存放有关变量的值,以减少对于内存的访问次数。另外,如何根据机器硬件执行指令的特点(如流水线、RISC、CISC、VLIW等)而对指令进行一些调整使目标代码比较短,执行的效率比较高,也是一个重要的研究课题。

汇编
通过汇编器将编译过程生成的汇编代码翻译为机器代码,并生成二进制可重定向文件.o。二进制可重定向文件主要包括二进制代码和数据,在链接阶段可以与其他二进制可重定向文件合并,由链接器生成可执行文件。
在这里插入图片描述

链接
将相关的可重定向文件进行链接,生成最终的可执行文件。
在编译阶段编译器和汇编器会生成每个文件的符号表,符号表中存放的是由程序产生的符号,比如函数名,变量名等,从上图可以看出,编译器没有给符号分配正确的地址(图中地址全为0000 0000),所以在代码段计算机指令无法找到相应的变量或函数的地址,因此,二进制可重定向文件是无法执行的。所以二进制可重定向文件得等到重定向以后才成为可执行文件。
程序的链接分为两个步骤:
第一步:链接器将多个可重定向文件相应的段进行合并,并建立映射关系和符号表的合并,进行符号解析(让所有符号的引用找到符号的定义),解析完成后给符号分配虚拟地址。
第二部:将分配好的虚拟地址与符号表中的符号一一对应起来,使其成为正确的指令,是代码段的指令可以根据符号的地址进行相应操作,最后由链接器生成可执行文件。

分为静态链接和动态链接
静态链接:
将程序代码从其所在的静态链接库中拷贝至可执行程序中,程序在执行时将被装入到进程的虚拟地址空间中,静态链接库是目标文件的集合,其中每个文件含有库中一个或一组相关函数的代码。
动态链接:
函数的代码被放到称作是动态链接库或者共享对象的某个目标文件中,最终可执行程序只是记录下了共享对象的名字和少量的登记信息,在可执行程序被执行时,动态链接库被映射到执行进行的虚拟地址空间中,动态链接库根据可执行文件中的记录信息找到相应的函数代码。
链接
链接

function函数和bind

c++的可调用对象包括:函数,函数指针,lambda表达式,bind函数对象,函数对象。
可调用对象的定义方式比较多,但是函数调用方式比较类似,因此需要使用一个统一的方式保存可调用对象或者传递可调用对象。
function是一个可调用对象的包装器,是一个类模板,可以容纳除了类成员函数指针之外的所有可调用对象,它可以使用统一的方式处理函数,函数指针,函数对象并允许保存和延迟他们的执行。
1.std::function对C++中各种可调用实体(普通函数、Lambda表达式、函数指针、以及其它函数对象等)的封装,形成一个新的可调用的std::function对象,简化调用
2.std::function对象是对C++中现有的可调用实体的一种类型安全的包裹(如:函数指针这类可调用实体,是类型不安全的)

bind可以看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来适应原对象的参数列表。
bind可将可调用对象和参数一起绑定,绑定后的结果使用function存储。
主要作用为:
1.将可调用对象与参数绑定成一个仿函数
2.只绑定部分参数,减少可调用对象传入参数的个数

预绑定的参数是以值传递的形式,不预绑定的参数要用std::placeholders(占位符)的形式占位,从_1开始,依次递增,是以引用传递的形式
std::placeholders表示新的可调用对象的第几个参数,而且与原函数的该占位符所在位置的进行匹配
bind绑定类成员函数时,第一个参数表示对象的成员函数的指针,第二个参数表示对象的地址,这是因为对象的成员函数需要有this指针。并且编译器不会将对象的成员函数隐式转换成函数指针,需要通过&手动转换
std::bind的返回值是可调用实体,可以直接赋给std::function

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值