这里介绍一些C++中的常见术语。

内存对齐

常量折叠

堆栈解退(stack unwinding)

模板全特化 vs 模板偏特化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
template<typename T1, typename T2>  
class Test {

public:
Test(T1 i, T2 j):a(i),b(j) {cout<<"模板类"<<endl;}

private:
T1 a;
T2 b;
};

template<>
class Test<int, char> {

public:
Test(int i, char j):a(i),b(j) {cout<<"全特化"<<endl;}

private:
int a;
char b;
};

template <typename T2>
class Test<char, T2> {

public:
Test(char i, T2 j):a(i),b(j) {cout<<"偏特化"<<endl;}

private:
char a;
T2 b;
};
1
2
3
Test<double, double> t1(0.1, 0.2);  // 类模板
Test<int, char> t2(1, 'A'); // 全特化
Test<char, bool> t3('A', true); // 偏特化

模板实例化

函数对象

单一定义规则(One-Definition Rule,ODR)

自引用

对象切片(object slicing)/切割

当把一个派生类对象赋给一个基类对象时,会发生对象切割。(另外用基类对象强制转换派生类对象也会),多态的实现是通过指针和引用;而对象的转换只会造成对象切割,不能实现多态。

所有权语义(owership semantics)#

破坏性复制语义(distructive copy semantics)#

菱形继承

向下强制

基类到派生类的转换

向上强制

派生类到基类的转换

交叉强制

从一个基类向其兄弟类的强制(多重继承中涉及)

RTTI

运行时类型信息,dynamic_cast,type_info

谓词

返回bool函数对象(或者函数),有一元谓词和二元谓词,标准库中有谓词

活动记录(activation record)#

堆栈帧(stack frame)/调用栈

using声明与using指令

内存中编译(in-memory compilation)

窥孔优化器(peephole optimizer)

易碎的基类问题(fragile base-class problem)

句柄类(handle class)#

可重入函数

位拷贝与值拷贝

位拷贝拷贝的是地址,而值拷贝则拷贝的是内容

浅拷贝(shallow copy)与深拷贝

返回值优化(return value optimization)#

引用计数(reference counting)

写拷贝/写时复制(copy-on-write)#

扇出(fan-out)#

重定义(redefining)#

子类重新定义父类中有相同名称的非虚函数 ( 参数列表可以不同 ) 。

覆盖/重写(overriding)#

父类与子类之间的多态性。子类重新定义父类中有相同名称和参数的虚函数。

重载(overload)#

多重指派(multiple dispatching)#

异常中立的(exception neutral)#

模板元编程

稳定排序与不稳定排序

惰性初始化(lazy initialization)#

多重赋值

函数调用栈(function call stack)#

逆变性与协变返回类型

继承树

资源获取即初始化RAII(resource acquisition is initialization)

关联名字查找ADL

内存泄露(memory leak)

野指针(wildpointer)

Liskov置换原则

定义

  1. 如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。
  2. 所有引用基类的地方必须能透明地使用其子类的对象。

里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。
它包含以下4层含义:

  1. 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
  2. 子类中可以增加自己特有的方法。
  3. 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
  4. 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

短路求值(short-circuit evaluation)#

返回值优化(Return Value Optimization RVO)

koenig查找:名字查找规则

C++ 运行时库

Reusable Library Switch Library Macro(s) Defined
Single Threaded /ML LIBC (none)
Static MultiThread /MT LIBCMT _MT
Dynamic Link (DLL) /MD MSVCRT _MT and _DLL
Debug Single Threaded /MLd LIBCD _DEBUG
Debug Static MultiThread /MTd LIBCMTD _DEBUG and _MT
Debug Dynamic Link (DLL) /MDd MSVCRTD _DEBUG, _MT, and _DLL

/MT和/MTd表示采用多线程CRT库的静态lib版本。该选项会在编译时将运行时库以静态lib的形式完全嵌入。该选项生成的可执行文件运行时不需要运行时库dll的参加,会获得轻微的性能提升,但最终生成的二进制代码因链入庞大的运行时库实现而变得非常臃肿。当某项目以静态链接库的形式嵌入到多个项目,则可能造成运行时库的内存管理有多份,最终将导致致命的“Invalid Address specified to RtlValidateHeap”问题。另外托管C++和CLI中不再支持/MT和/MTd选项。

/MD和/MDd表示采用多线程CRT库的动态dll版本,会使应用程序使用运行时库特定版本的多线程DLL。链接时将按照传统VC链接dll的方式将运行时库MSVCRxx.DLL的导入库MSVCRT.lib链接,在运行时要求安装了相应版本的VC运行时库可再发行组件包(当然把这些运行时库dll放在应用程序目录下也是可以的)。 因/MD和/MDd方式不会将运行时库链接到可执行文件内部,可有效减少可执行文件尺寸。当多项目以MD方式运作时,其内部会采用同一个堆,内存管理将被简化,跨模块内存管理问题也能得到缓解。

不要混合使用运行时库的静态版本和动态版本。在一个进程中有多个运行时库副本会导致问题,因为副本中的静态数据不与其他副本共享。链接器禁止在 .exe 文件内部既使用静态版本又使用动态版本链接,但您仍可以使用运行时库的两个(或更多)副本。例如,当与用动态 (DLL) 版本的运行时库链接的 .exe 文件一起使用时,用静态(非 DLL)版本的运行时库链接的动态链接库可能导致问题。(还应该避免在一个进程中混合使用这些库的调试版本和非调试版本)。

官方说明

C 运行时库 (CRT)

C 运行时库 (CRT) 是集成了 ISO C99 标准库的 C++ 标准库。 实现 CRT 的 Visual C++ 库支持用于 .NET 开发的本机代码开发以及本机和托管混合代码。 所有版本的 CRT 都支持多线程开发。 大多数的库都支持通过静态链接将库直接链接到代码中,或通过动态链接让代码使用常用 DLL 文件。

从 Visual Studio 2015 开始,CRT 已被重构为新的二进制文件。 通用 CRT (UCRT) 包含通过标准 C99 CRT 库导出的函数和全局函数。 UCRT 现为 Windows 组件,并作为 Windows 10 的一部分提供。 静态库、DLL 导入库和 UCRT 的头文件现在 Windows 10 SDK 中提供。 安装 Visual C++ 时,Visual Studio 安装程序将安装使用 UCRT 所需 Windows 10 SDK 的子集。 可以在 Visual Studio 2015 及更高版本支持的任何 Windows 版本上使用 UCRT。 可以使用 vcredist 重新分发它,以便支持 Windows 10 以外的 Windows 版本。

库 关联的 DLL 特征 选项 预处理器指令
libucrt.lib 无 将 UCRT 静态链接到你的代码。 /MT _MT
libucrtd.lib 无 用于静态链接的 UCRT 调试版本。不可再发行。 /MTd _DEBUG, _MT
ucrt.lib ucrtbase.dll UCRT 的 DLL 导入库。 /MD _MT, _DLL
ucrtd.lib ucrtbased.dll UCRT 调试版本的 DLL 导入库。 不可再发行。 /MDd _DEBUG, _MT, _DLL

vcruntime 库包含 Visual C++ CRT 实现特定的代码,例如异常处理和调试支持、运行时检查和类型信息、实现的详细信息和某些扩展的库函数。 此库特定于所用编译器的版本。

库 关联的 DLL 特征 选项 预处理器指令
libvcruntime.lib 无 静态链接到你的代码。 /MT _MT
libvcruntimed.lib 无 用于静态链接的调试版本。 不可再发行。 /MTd _MT, _DEBUG
vcruntime.lib vcruntime.dll vcruntime 的 DLL 导入库。 /MD _MT, _DLL
vcruntimed.lib vcruntimed.dll 调试 vcruntime 的 DLL 导入库。不可再发行。 /MDd _DEBUG, _MT, _DLL
库 特征 选项 预处理器指令
LIBCMT.lib 将本机 CRT 启动静态链接到你的代码。 /MT _MT
libcmtd.lib 静态链接本机 CRT 启动的调试版本。 不可再发行。 /MTd _DEBUG, _MT
msvcrt.lib 与 DLL UCRT 和 vcruntime 一起使用的本机 CRT 启动的静态库。 /MD _MT, _DLL
msvcrtd.lib 与 DLL UCRT 和 vcruntime 一起使用的本机 CRT 启动调试版本的静态库。不可再发行。 /MDd _DEBUG, _MT, _DLL
msvcmrt.lib 与 DLL UCRT 和 vcruntime 一起使用的本机和托管混合 CRT 启动的静态库。 /clr
msvcmrtd.lib 与 DLL UCRT 和 vcruntime 一起使用的本机和托管混合 CRT 启动调试版本的静态库。 不可再发行。 /clr

C++ 标准库

C运行库功能

C运行时库参考

常用的VC编译器指令

其他知识汇总

ABI(Application Binary Interface)

动态库调用方式

显示调用(Run-time Dynamic Linking)

这种方式是指在编译之前并不知道将会调用哪些DLL函数,完全是在运行过程中根据需要决定应调用哪个函数,并用LoadLibrary和GetProcAddress动态获得DLL函数的入口地址。

隐式调用(Load-time Dynamic Linking)

这种用法的前提是在编译之前已经明确知道要调用DLL中的哪几个函数,编译时在目标文件中只保留必要的链接信息,而不含DLL函数的代码;当程序执行时,利用链接信息加载DLL函数代码并在内存中将其链接入调用程序的执行空间中,其主要目的是便于代码共享。