自由存储区是否等价于堆区
“free store” and “heap”当谈及 C++ 的内存分布时,通常会想到:
C++ 中,内存分区为 5 个区,分别为堆,栈,自由存储区,全局/静态存储区,常量存储区。
自由存储区(free store) 和堆区(heap) 有什么区别呢?
malloc 在堆上分配内存块,使用 free 释放内存,而 new 申请的内存则是在自由存储区上,使用 delete 来释放
自由存储区是与堆区是两块不同的区域吗?它们有可能相同吗?这时候需要知道:所谓的划分自由存储区与堆区的分界线是 new/delete 与 malloc/free ,然而 C++ 没有标准要求,很多编译器的 new/delete 都是以 malloc/free 为基础来实现的。
借以 malloc 实现的 new ,所申请的内存实在堆上还是在自由存储区上?
从技术上来说,堆是 C语言 和操作系统的术语。堆是一块操作系统维护的特殊内存,提供了动态分配的功能,当运行程序调用malloe()时就会从中分配,稍后调用free可把内存交还。
而自由存储是 C++ ...
dynamic_cast
dynamic_cast
用于多态类型的转换
执行行运行时类型检查
只适用于指针或引用
对不明确的指针的转换将失败(返回 nullptr),但不引发异常
可以在整个类层次结构中移动指针,包括向上转换、向下转换
自由存储区是否等价于堆区
ID
Circumstance
Provenance
1
代码行以反斜杠结尾,且与下一行连接后生成通用字符名称
11-2.2(2)
2
非空源文件未以换行符结尾,或以换行符结尾但换行符之前是反斜杠
03-2.1(2)
3
连接预处理符号时产生了通用字符名称
11-2.2(4)
4
存在不符合词法的单引号或双引号
11-2.5(2)
5
在 #include 指令中,’、”、\、//、/* 出现在定界符 < > 之间,或 ‘、\、//、/* 出现在定界符 “ 之间
03-2.8(2)
6
无后缀 10 进制整数字面常量超过 long int 取值范围
03-2.13.1(2)
7
使用非标准转义字符
03-2.13.2(3)
8
修改字符串字面常量
11-2.14.5(12)
9
窄字符串与宽字符串连接
03-2.13.4(3)
10
违反 One Definition Rule
11-3.2(5)
11
具有静态或线程存储期的对象在析构函数中调用 std::ex ...
内联函数
inline 说明符整个定义都在 class/struct/union 的定义内的函数,若非被附着到具名模块, (C++20 起)都是隐式的内联函数,无论它是成员函数还是非成员 friend 函数。
首个声明有 constexpr 或 consteval (C++20 起) 的函数是隐式的内联函数。
弃置的函数是隐式的内联函数:它的(弃置)定义可以在多于一个翻译单元中出现。
特征
相当于把内联函数里面的内容写在调用内联函数处;
相当于不用执行进入函数的步骤,直接执行函数体;
相当于宏,却比宏多了类型检查,真正具有函数特性;
编译器一般不内联包含循环、递归、switch 等复杂操作的内联函数;
在类声明中定义的函数,除了虚函数的其他函数都会自动隐式地当成内联函数。
编译器对 inline 函数的处理步骤
将 inline 函数体复制到 inline 函数调用点处;
为所用 inline 函数中的局部变量分配内存空间;
将 inline 函数的的输入参数和返回值映射到调用方法的局部变量空间中;
如果 inline 函数有多个返回点,将其转变为 inline 函数代码块 ...
lambda
第一题1auto* p = +[] {return 6; };
这里的 + 是什么作用?这是一个非捕获的 lambda,自然可以生成对应转换函数转换为函数指针,这里的一元 + 是为了辅助推导,是为了创造合适的语境。自然理解为使用转换函数返回函数指针,+ 指针,符合规范
这里 auto* 的 * 可以去掉
第二题1234567int main() { static int a = 42; auto p = [=] { ++a; } ; std::cout << sizeof p << '\n'; p(); return a;}
提问,打印p是多少?return a是多少?
答案: 1 43
解释:
如果变量满足下列条件,那么 lambda 表达式在使用它前不需要先捕获:该变量是非局部变量,或具有静态或线程局部存储期(此时无法捕获该变量),或者该变量是以常量表达式初始化的引用。
这里的捕获是 [=] ,但是其实写不写都无所谓,反正这个作用域就一个 ...
new 和 delete
new、delete 是线程安全的吗?如果标准达到 C++11,要求下列函数是线程安全的:
new 运算符和 delete 运算符的库版本
全局 new 运算符和 delete 运算符的用户替换版本
std::calloc、std::malloc、std::realloc、std::aligned_alloc (C++17 起)、std::free
举个例子:
1234void f(){ T* p = new T{}; delete p;}
内存分配、释放操作是线程安全,构造和析构不涉及共享资源。而局部对象 p 对于每个线程来说是独立的。换句话说,每个线程都有其自己的 p 对象实例,因此它们不会共享同一个对象,自然没有数据竞争。
如果 p 是全局对象(或者外部的,只要可被多个线程读写),多个线程同时对其进行访问和修改时,就可能会导致数据竞争和未定义行为。因此,确保全局对象的线程安全访问通常需要额外的同步措施,比如互斥量或原子操作。
12345T* p = nullptr;void f(){ p = new T& ...
sizeof 运算符
sizeofsizeof( 类型 ) (1) sizeof 表达式 (2)
产生 类型 的对象表示的字节数。
产生 表达式 的类型的对象表示的字节数,假如该表达式被求值。
不能对函数类型、不完整类型或位域左值(C++11 前) 泛左值(C++11 起)使用 sizeof。
当应用于引用类型时,结果是被引用类型的大小。
sizeof 的结果始终非零,即使应用于空类。
当应用于某个表达式时,sizeof 并不对表达式进行求值(即该表达式是不求值操作数)(C++11 起),并且即便表达式代表多态对象,它的结果也是该表达式的静态类型的大小。不进行左值向右值、数组向指针和函数向指针转换。不过,它在形式上对纯右值实参进行临时量实质化:实参不可析构时程序非良构。 (C++17 起)