C++基础总结

it2022-05-05  194

杂项

C++基础知识函数指针C++类型函数返回多个值的方法C11内存持续性智能指针函数内联类中内联的4种方式 explicit函数栈框架decltype推导四准则通用引用类型转换系统调用

C++基础知识

函数指针

函数指针作用:

提供调用的灵活性,例如qsort中的排序,是选择排大,还是排小实现面向对象编程中的多态性回调函数简化结构和程序通用性

typedef const double* (p_fun)(const double d);//p_fun是一种typename,而不是函数指针 void (*fun(int (*arg)(void)))(void); // 返回值为void()函数指针,形参为int ()函数指针,函数名为fun

C++类型

类默认成员为private,结构体默认为public空结构体和类大小为1,空类也可以实例化,类实例化出的每个对象都需要有不同的内存地址,为使每个对象在内存中的地址不同,所以在类中会加入一个隐含字节成员变量在类中的内存存储并不一定是连续的。它是按照编译器的设置,按照内存块来存储的,这个内存块大小的取值,就是内存对齐。vs中使用#pragma pack(1)宏可以更改块的大小 位字段无法用sizeof获取内存大小结构体变量中的成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍)结构体大小必须是所有成员大小的整数倍,也即所有成员大小的整数倍类成员构造顺序:基类静态成员 – 子类静态成员 – (设置v_ptr/基类成员变量 ) –基类构造函数 – (设置v_ptr/子类成员变量) – 子类构造函数

函数返回多个值的方法

把返回值打包返回,如返回一个数组名,指针,结构体函数外定义,函数类修改

C11内存持续性

自动存储持续性:栈内存中的变量静态存储持续性:使用static定义的变量,程序运行整个过程线程存储持续性:使用Local_thread修饰的变量,线程生命周期动态存储持续性:直到delete或free

智能指针

有3种方案来管理内部指针:

delete掉复制构造,复制拷贝引用计数底层复制,即复制内部指针指向的内存

Share_ptr:采用方案二,引用计数,但是存在内存泄漏的风险(相互引用) Unique_ptr:采用方案一,用来替代auto_ptr Weak_ptr:用来处理share_ptr相互引用的内存泄漏问题,由Share_ptr生成,但不会增加Share_ptr计数,同时也不会管理对象生命 auto_ptr:被摈弃

函数内联

添加inline标识符,编译器不一定会采用内联,编译器需要支持内联,函数过大,递归函数与宏定义不同,宏定义通过文本替换实现,而内联是参数传递

类中内联的4种方式

1、 隐式内联,实现在类中 2、 显示内联,类里声明inline,类中或类外实现 3、 追加内联,类中不声明inline,类外声明并实现inline 4、 非内联,定义和申明都没有inline 返回值类型确定: 1、返回指向const对象的引用 2、返回非const对象引用 常见引用目的提高效率,免去复制构造和析构,非const典型为cout,连续操作对象 3、返回对象 函数体内的临时变量 4、返回const对象 示例:加法运算: Vector Vector::operator+() o1 + o2 = o3;//正确运行 应该修改为const Vector Vector:operator+(); o1 + o2 = o3;//会报错

explicit

只有单个参数的构造方法,才会可能隐式转换,explicit必须显示调用,隐式转换的可能: 1、 将Class对象初始化为double值 2、 将double值赋值给Class对象 3、 将double值传递给接受Class对象参数的函数时 4、 返回值为Class对象时,返回double值 5、 在上述任意一种情况下,使用可转换为double类型的内置类型时

函数栈框架

一个进程中可以同时包含多个线程。 我们通常认为线程是操作系统可识别的最小并发执行和调度单位。 同一进程中的多个线程共享代码段(代码和常量)、数据段(静态和全局变量)和扩展段(堆存储),但是每个线程有自己的栈段。栈段又叫运行时栈,用来存放所有局部变量和临时变量(参数、返回值、临时构造的变量等)。这一条对下文中的某些概念来说是非常重要的 。但是请注意,这里提到的各个“段”都是逻辑上的说法,在物理上某些硬件架构或者操作系统可能不使用段式存储。不过没关系,编译器会保证这些逻辑概念和假设的前提条件对每个 C/C++ 程序员来说始终是成立的。 一般来说,编译器会为当前调用栈里的每个函数建立一个栈框架(Stack Frame)。“栈框架”担负着以下重要任务: 传递参数:通常,函数的调用参数总是在这个函数栈框架的最顶端。 传递返回地址:告诉被调用者的 return 语句应该 return 到哪里去,通常指向该函数调用的下一条语句(代码段中的偏移)。 存放调用者的当前栈指针:便于清理被调用者的所有局部变量、并恢复调用者的现场。 存放当前函数内的所有局部变量:记得吗?刚才说过所有局部和临时变量都是存储在栈上的。  由于共享了除栈以外的所有内存地址段,线程不可以有自己的“静态”或“全局”变量,为了弥补这一缺憾,操作系统通常会提供一种称为 TLS(Thread Local Storage,即:“线程本地存储”)的机制。通过该机制可以实现类似的功能。TLS 通常是线程控制块(TCB)中的某个指针所指向的一个指针数组,数组中的每个元素称为一个槽(Slot),每个槽中的指针由使用者定义,可以指向任意位置(但通常是指向堆存储中的某个偏移)。

decltype推导四准则

decltype推导四规则

如果e是一个没有带括号的标记符表达式或者类成员访问表达式,那么的decltype(e)就是e所命名的实体的类型。此外,如果e是一个被重载的函数,则会导致编译错误。否则 ,假设e的类型是T,如果e是一个将亡值,那么decltype(e)为T&&否则,假设e的类型是T,如果e是一个左值,那么decltype(e)为T&。否则,假设e的类型是T,则decltype(e)为T。 标记符指的是除去关键字、字面量等编译器需要使用的标记之外的程序员自己定义的标记,而单个标记符对应的表达式即为标记符表达式。

通用引用

通用引用只在类型推导时会出现:

函数模板参数(function template parameters)auto声明(auto declaration)auto && var = …;typedef声明(typedef declaration)decltype声明(decltype declaration)

只有在通用应用中才会出现引用合成

类型转换

static_cast 转换失败抛出异常,向下转换不会进行类型检查 dynamic_cast支持交叉转换,转换失败返回空指针,向下转换会进行类型检查判断

系统调用

频繁调用系统内核函数会导致性能降低,因为程序进入内核态时,系统会将程序封装保存,在切入内核态,返回切换会导致性能降低


最新回复(0)