From 58d0e8b3bfc3e487885f4dfa10e36b8368e9048c Mon Sep 17 00:00:00 2001 From: huihut Date: Sun, 6 Mar 2022 14:48:55 +0800 Subject: [PATCH 01/20] =?UTF-8?q?=E4=BF=AE=E6=AD=A3TCP=E9=87=8A=E6=94=BE?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E8=BF=87=E7=A8=8B=E6=96=87=E6=9C=AC=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/huihut/interview/issues/81 --- README.md | 2 +- README_en.md | 4 ++-- docs/README.md | 2 +- docs/en.md | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 220481a7..2ba74cb4 100644 --- a/README.md +++ b/README.md @@ -2358,7 +2358,7 @@ TCP的拥塞控制图 3. 客户端收到服务端回复的 ACK,此时从客户端到服务器的连接已释放(但服务端到客户端的连接还未释放,并且客户端还可以接收数据); 4. 服务端继续发送之前没发完的数据给客户端; 5. 服务端发送 FIN+ACK 给客户端,说明服务端发送完了数据(请求释放从服务端到客户端的连接,就算没收到客户端的回复,过段时间也会自动释放); -6. 客户端收到服务端的 FIN+ACK,并回复 ACK 给客户端(同意释放从服务端到客户端的连接); +6. 客户端收到服务端的 FIN+ACK,并回复 ACK 给服务端(同意释放从服务端到客户端的连接); 7. 服务端收到客户端的 ACK 后,释放从服务端到客户端的连接。 ##### TCP 为什么要进行四次挥手? diff --git a/README_en.md b/README_en.md index ef6a2e66..979ef9bd 100644 --- a/README_en.md +++ b/README_en.md @@ -2348,7 +2348,7 @@ TCP Congestion control graph > ["Computer Network (7th Edition) -Xie Xiren"](https://raw.githubusercontent.com/huihut/interview/master/images/TCP-transport-connection-management.png) -##### TCP 四次挥手释放连接 +##### TCP Four waves to release the connection ![UDP 报文](https://raw.githubusercontent.com/huihut/interview/master/images/TCP四次挥手释放连接.png) @@ -2359,7 +2359,7 @@ TCP Congestion control graph 3. The client receives the ACK from the server, and the connection from the client to the server has been released (but the connection from the server to the client has not been released, and the client can still receive data); 4. The server continues to send the unfinished data to the client; 5. The server sends FIN + ACK to the client, indicating that the server has sent the data (request to release the connection from the server to the client, even if no reply is received from the client, it will be automatically released after a certain period of time); -6. The client receives the FIN + ACK from the server and replies to the client with an ACK (agreeing to release the connection from the server to the client); +6. The client receives the FIN + ACK from the server and replies to the server with an ACK (agreeing to release the connection from the server to the client); 7. After receiving the ACK from the client, the server releases the connection from the server to the client. ##### Why does TCP have to wave four times? diff --git a/docs/README.md b/docs/README.md index 8f000cee..5385854d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2351,7 +2351,7 @@ TCP的拥塞控制图 3. 客户端收到服务端回复的 ACK,此时从客户端到服务器的连接已释放(但服务端到客户端的连接还未释放,并且客户端还可以接收数据); 4. 服务端继续发送之前没发完的数据给客户端; 5. 服务端发送 FIN+ACK 给客户端,说明服务端发送完了数据(请求释放从服务端到客户端的连接,就算没收到客户端的回复,过段时间也会自动释放); -6. 客户端收到服务端的 FIN+ACK,并回复 ACK 给客户端(同意释放从服务端到客户端的连接); +6. 客户端收到服务端的 FIN+ACK,并回复 ACK 给服务端(同意释放从服务端到客户端的连接); 7. 服务端收到客户端的 ACK 后,释放从服务端到客户端的连接。 ##### TCP 为什么要进行四次挥手? diff --git a/docs/en.md b/docs/en.md index 91dac884..6720f339 100644 --- a/docs/en.md +++ b/docs/en.md @@ -2339,7 +2339,7 @@ TCP Congestion control graph > ["Computer Network (7th Edition) -Xie Xiren"](https://raw.githubusercontent.com/huihut/interview/master/images/TCP-transport-connection-management.png) -##### TCP 四次挥手释放连接 +##### TCP Four waves to release the connection ![UDP 报文](https://raw.githubusercontent.com/huihut/interview/master/images/TCP四次挥手释放连接.png) @@ -2350,7 +2350,7 @@ TCP Congestion control graph 3. The client receives the ACK from the server, and the connection from the client to the server has been released (but the connection from the server to the client has not been released, and the client can still receive data); 4. The server continues to send the unfinished data to the client; 5. The server sends FIN + ACK to the client, indicating that the server has sent the data (request to release the connection from the server to the client, even if no reply is received from the client, it will be automatically released after a certain period of time); -6. The client receives the FIN + ACK from the server and replies to the client with an ACK (agreeing to release the connection from the server to the client); +6. The client receives the FIN + ACK from the server and replies to the server with an ACK (agreeing to release the connection from the server to the client); 7. After receiving the ACK from the client, the server releases the connection from the server to the client. ##### Why does TCP have to wave four times? From c55256a15ef8eddd1393eb680f3edeb73e15b165 Mon Sep 17 00:00:00 2001 From: wr786 Date: Thu, 17 Mar 2022 21:18:34 +0800 Subject: [PATCH 02/20] fix: typo in inline --- README.md | 2 +- docs/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2ba74cb4..848fb8ae 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,7 @@ inline int A::doA() { return 0; } // 需要显式内联 > [Are "inline virtual" member functions ever actually "inlined"?](http://www.cs.technion.ac.il/users/yechiel/c++-faq/inline-virtuals.html) * 虚函数可以是内联函数,内联是可以修饰虚函数的,但是当虚函数表现多态性的时候不能内联。 -* 内联是在编译器建议编译器内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时(运行期)不可以内联。 +* 内联是在编译期建议编译器内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时(运行期)不可以内联。 * `inline virtual` 唯一可以内联的时候是:编译器知道所调用的对象是哪个类(如 `Base::who()`),这只有在编译器具有实际对象而不是对象的指针或引用时才会发生。 虚函数内联使用 diff --git a/docs/README.md b/docs/README.md index 5385854d..d6a5b4a0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -210,7 +210,7 @@ inline int A::doA() { return 0; } // 需要显式内联 > [Are "inline virtual" member functions ever actually "inlined"?](http://www.cs.technion.ac.il/users/yechiel/c++-faq/inline-virtuals.html) * 虚函数可以是内联函数,内联是可以修饰虚函数的,但是当虚函数表现多态性的时候不能内联。 -* 内联是在编译器建议编译器内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时(运行期)不可以内联。 +* 内联是在编译期建议编译器内联,而虚函数的多态性在运行期,编译器无法知道运行期调用哪个代码,因此虚函数表现为多态性时(运行期)不可以内联。 * `inline virtual` 唯一可以内联的时候是:编译器知道所调用的对象是哪个类(如 `Base::who()`),这只有在编译器具有实际对象而不是对象的指针或引用时才会发生。 虚函数内联使用 From 5b485e93261afc800002c65f809890233604f8c9 Mon Sep 17 00:00:00 2001 From: KemGong Date: Tue, 25 Apr 2023 11:04:47 +0800 Subject: [PATCH 03/20] [fix] add BridgeMain() --- DesignPattern/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DesignPattern/main.cpp b/DesignPattern/main.cpp index cf99dec9..b8d3b055 100644 --- a/DesignPattern/main.cpp +++ b/DesignPattern/main.cpp @@ -32,7 +32,8 @@ int main() { std::cout << "*******************" << std::endl; std::cout << "** Bridge mode **" << std::endl; std::cout << "*******************" << std::endl; - + BridgeMain(); + std::cout << "*******************" << std::endl; std::cout << "** Observer mode **" << std::endl; std::cout << "*******************" << std::endl; From 65f8318948df4b91ae99c802d55d549389c06c28 Mon Sep 17 00:00:00 2001 From: SPeak Date: Tue, 13 Jun 2023 17:26:52 +0800 Subject: [PATCH 04/20] =?UTF-8?q?=E5=90=8D=E8=AF=8D=E9=A3=8E=E6=A0=BC:=20?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E7=B1=BB=20to=20=E7=B1=BB=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 统一名词风格: 模板类 to 类模板 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 848fb8ae..2fe45a63 100644 --- a/README.md +++ b/README.md @@ -939,9 +939,9 @@ virtual int A() = 0; * 虚函数不占用存储空间 * 虚函数表存储的是虚函数地址 -### 模板类、成员模板、虚函数 +### 类模板、成员模板、虚函数 -* 模板类中可以使用虚函数 +* 类模板中可以使用虚函数 * 一个类(无论是普通类还是类模板)的成员模板(本身是模板的成员函数)不能是虚函数 ### 抽象类、接口类、聚合类 From 77b04416e2c7b60750ca3740c2c12e1ee6374500 Mon Sep 17 00:00:00 2001 From: huihut Date: Tue, 20 Jun 2023 21:28:23 +0800 Subject: [PATCH 05/20] Remove sponsor --- README.md | 7 ------- README_en.md | 7 ------- docs/README.md | 7 ------- docs/en.md | 7 ------- 4 files changed, 28 deletions(-) diff --git a/README.md b/README.md index 2fe45a63..45d8f22e 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,6 @@ * [📆 招聘时间岗位](#recruitment-time-post) * [👍 内推](#recommend) * [👬 贡献者](#contributor) -* [🍭 支持赞助](#support-sponsor) * [📜 License](#license) @@ -3433,12 +3432,6 @@ int main( void ) - - -## 🍭 支持赞助 - -**[Avalive](https://store.steampowered.com/app/1137770/Avalive/)**:一个面部捕捉的虚拟形象扮演软件。 - ## 📜 License diff --git a/README_en.md b/README_en.md index 979ef9bd..0ebb0e9f 100644 --- a/README_en.md +++ b/README_en.md @@ -49,7 +49,6 @@ English * [📆 Recruitment time post](#recruitment-time-post) * [👍 Recommend](#recommend) * [👬 Contributor](#contributor) -* [🍭 Support Sponsor](#support-sponsor) * [📜 License](#license) @@ -3435,12 +3434,6 @@ contain: - - -## 🍭 Support sponsorship - -**[Avalive](https://store.steampowered.com/app/1137770/Avalive/)** - A avatar role-playing software for facial capture. - ## 📜 License diff --git a/docs/README.md b/docs/README.md index d6a5b4a0..1f678524 100644 --- a/docs/README.md +++ b/docs/README.md @@ -38,7 +38,6 @@ * [📆 招聘时间岗位](#recruitment-time-post) * [👍 内推](#recommend) * [👬 贡献者](#contributor) -* [🍭 支持赞助](#support-sponsor) * [📜 License](#license) @@ -3426,12 +3425,6 @@ int main( void ) - - -## 🍭 支持赞助 - -**[Avalive](https://store.steampowered.com/app/1137770/Avalive/)**:一个面部捕捉的虚拟形象扮演软件。 - ## 📜 License diff --git a/docs/en.md b/docs/en.md index 6720f339..4b4c175b 100644 --- a/docs/en.md +++ b/docs/en.md @@ -42,7 +42,6 @@ * [📆 Recruitment time post](#recruitment-time-post) * [👍 Recommend](#recommend) * [👬 Contributor](#contributor) -* [🍭 Support Sponsor](#support-sponsor) * [📜 License](#license) @@ -3426,12 +3425,6 @@ contain: - - -## 🍭 Support sponsorship - -**[Avalive](https://store.steampowered.com/app/1137770/Avalive/)** - A avatar role-playing software for facial capture. - ## 📜 License From 1ba799bb789f4ac4c3e7d8719bda8c5c599027be Mon Sep 17 00:00:00 2001 From: huihut Date: Thu, 24 Jul 2025 21:50:58 +0800 Subject: [PATCH 06/20] Fix using namespace_name https://github.com/huihut/interview/issues/121 --- README.md | 2 +- README_en.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 45d8f22e..eea1aadf 100644 --- a/README.md +++ b/README.md @@ -566,7 +566,7 @@ Derived(parms) : Base(args) { } `using 指示` 使得某个特定命名空间中所有名字都可见,这样我们就无需再为它们添加任何前缀限定符了。如: ```cpp -using namespace_name name; +using namespace namespace_name; ``` #### 尽量少使用 `using 指示` 污染命名空间 diff --git a/README_en.md b/README_en.md index 0ebb0e9f..a30ea265 100644 --- a/README_en.md +++ b/README_en.md @@ -544,7 +544,7 @@ int main() A `using declaration` introduces only one member of a namespace at a time. It allows us to know exactly which name is referenced in the program. Such as: ```cpp -using namespace_name :: name; +using namespace_name::name; ``` #### Using declaration of constructor @@ -570,7 +570,7 @@ Derived (parms): Base (args) {} The `using directive` makes all names in a particular namespace visible, so we don't need to add any prefix qualifiers to them. Such as: ```cpp -using namespace_name name; +using namespace namespace_name; ``` #### Minimize `using directives` to pollute namespaces From d06047211271e6fc0298f39240e929b01b9f0822 Mon Sep 17 00:00:00 2001 From: huihut Date: Thu, 24 Jul 2025 22:45:33 +0800 Subject: [PATCH 07/20] =?UTF-8?q?Fix=20extern=20=E2=80=9CC=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/huihut/interview/issues/114 --- README.md | 12 ++++++------ README_en.md | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index eea1aadf..fdfe09a4 100644 --- a/README.md +++ b/README.md @@ -322,14 +322,14 @@ Bit mode: 2; // mode 占 2 位 * 位域的类型必须是整型或枚举类型,带符号类型中的位域的行为将因具体实现而定 * 取地址运算符(&)不能作用于位域,任何指针都无法指向类的位域 -### extern "C" +### extern 与 extern "C" -* 被 extern 限定的函数或变量是 extern 类型的 -* 被 `extern "C"` 修饰的变量和函数是按照 C 语言方式编译和链接的 +* `extern` 是存储类说明符(storage-class-specifier),用于声明变量或函数具有外部链接,表示实体的定义可能在其他翻译单元中。 +* `extern "C"` 是链接指示(linkage directive),它指定函数或变量使用 C 语言链接(不影响编译规则)。 + 1. 禁止 C++ 名称修饰。确保符号名称与该平台下 C 编译器生成的名称一致,避免链接时因名称修饰导致的未定义符号错误,但不保证平台 ABI(应用二进制接口)一致性。 + 2. 实现 C/C++ 互操作。允许 C++ 函数被 C 代码调用(或反之)。 -`extern "C"` 的作用是让 C++ 编译器将 `extern "C"` 声明的代码当作 C 语言代码处理,可以避免 C++ 因符号修饰导致代码不能和C语言库中的符号进行链接的问题。 - -extern "C" 使用 +`extern "C"` 使用 ```cpp #ifdef __cplusplus diff --git a/README_en.md b/README_en.md index a30ea265..b4a630b3 100644 --- a/README_en.md +++ b/README_en.md @@ -327,14 +327,14 @@ A class can define its (non-static) data members as bit-fields, which contain a * The type of the bit field must be an integer or enumerated type. The behavior of the bit field in a signed type will depend on the implementation. * The fetch operator (&) cannot be applied to the bit field, and no pointer can point to the bit field of the class -### extern "C" +### `extern` vs `extern "C"` -* Extern-qualified functions or variables are of type extern -* Variables and functions decorated with `extern" C "` are compiled and linked in C +* `extern` is a **storage-class specifier** used to declare that a variable or function has **external linkage**, indicating that the entity's definition may reside in another translation unit. +* `extern "C"` is a **linkage directive** that specifies functions or variables should use **C language linkage** (without affecting compilation rules). + 1. **Suppresses C++ name mangling**: Ensures symbol names match those generated by the C compiler _on that specific platform_, preventing undefined symbol errors during linking due to name decoration. **Does not guarantee platform ABI (Application Binary Interface) consistency**. + 2. **Enables C/C++ interoperability**: Allows C++ functions to be called from C code (and vice versa). -The function of `extern" C "` is to let the C ++ compiler treat the code declared by `extern" C "` as C language code, which can avoid the problem that the code cannot be linked with the symbols in the C language library due to symbol modification. . - -extern "C" demo +`extern "C"` demo ```cpp #ifdef __cplusplus From b7408d80ef1429c971a7ad36b374304260a0cdff Mon Sep 17 00:00:00 2001 From: huihut Date: Fri, 25 Jul 2025 20:39:46 +0800 Subject: [PATCH 08/20] fix Casting Operators https://github.com/huihut/interview/issues/113 --- README.md | 69 ++++++++++++++++++++++++++++++++++------------------ README_en.md | 67 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 89 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index fdfe09a4..2373a616 100644 --- a/README.md +++ b/README.md @@ -1097,37 +1097,62 @@ unique_ptr 是 C++11 才开始提供的类型,是一种在异常时可以帮 #### static_cast -* 用于非多态类型的转换 -* 不执行运行时类型检查(转换安全性不如 dynamic_cast) -* 通常用于转换数值数据类型(如 float -> int) -* 可以在整个类层次结构中移动指针,子类转化为父类安全(向上转换),父类转化为子类不安全(因为子类可能有不在父类的字段或方法) - -> 向上转换是一种隐式转换。 +* 编译时类型转换(无运行时检查) +* 不依赖 RTTI + +| 转换类型 | 安全性 | 示例 | +|--------------------------|--------------|--------------------------| +| 数值类型转 | ✅ 安全 | `float f=3.14; int i=static_cast(f);` | +| 类向上转换 | ✅ 安全 | `Derived* d; Base* b=static_cast(d);` | +| 类向下转换 | ⚠️ 不安全 | `Base* b=new Base; Derived* d=static_cast(b);` | +| 类不变转换 | ✅ 安全 | `MyClass* p; MyClass* same=static_cast(p);` | +| 显式构造函数调用 | ✅ 安全 | `func(static_cast("text"));` | +| 任意→void* | ✅ 安全 | `int* p; void* vp=static_cast(p);` | +| 枚举↔整型 | ✅ 安全 | `enum Color{RED}; int c=static_cast(RED);` | #### dynamic_cast -* 用于多态类型的转换 -* 执行行运行时类型检查 -* 只适用于指针或引用 -* 对不明确的指针的转换将失败(返回 nullptr),但不引发异常 -* 可以在整个类层次结构中移动指针,包括向上转换、向下转换 +* 运行时类型检查(依赖 RTTI) +* 多态类型要求(基类需至少一个虚函数) +* 安全失败机制(nullptr 或异常) + +| 转换类型 | 安全性 | 运行时开销 | 多态要求 | 失败处理 | 示例 | +|--------------|--------|------------|----------|------------------------|------| +| 类向上转换 | ✅ 安全 | 无 | ❌ 不需要 | 不适用(总是成功) | `Derived* d; Base* b = dynamic_cast(d);` | +| 类向下转换 | ✅ 安全 | 有 | ✅ 需要 | 指针→`nullptr`
引用→`std::bad_cast` | `Base* b=new Base; Derived* d = dynamic_cast(b);` | +| 类旁支转换 | ✅ 安全 | 有 | ✅ 需要 | 指针→`nullptr`
引用→`std::bad_cast` | `B2* b2 = dynamic_cast(b1); // 菱形继承中 B1*→B2*` | +| 类不变转换 | ✅ 安全 | 无 | ❌ 不需要 | 不适用(总是成功) | `Derived* d2 = dynamic_cast(d1);` | +| 任意→void* | ✅ 安全 | 有 | ✅ 需要 | `nullptr` | `void* p = dynamic_cast(obj);` | -#### const_cast +#### const_cast -* 用于删除 const、volatile 和 __unaligned 特性(如将 const int 类型转换为 int 类型 ) +* 编译时类型修饰符操作 +* 仅修改 `const`/`volatile` 属性 +* 不改变底层二进制表示 + +| 转换类型 | 安全性 | 示例 | +|------------------------|--------------|-------------------------------| +| 移除 const | ⚠️ 风险 | `const int* cp; int* p=const_cast(cp);` | +| 移除 volatile | ⚠️ 风险 | `volatile int* vp; int* p=const_cast(vp);` | +| 添加 const | ✅ 安全 | `int* p; const int* cp=const_cast(p);` | +| 兼容旧式 API | ⚠️ 必要风险 | `legacy_api(const_cast(str.c_str()));` | #### reinterpret_cast -* 用于位的简单重新解释 -* 滥用 reinterpret_cast 运算符可能很容易带来风险。 除非所需转换本身是低级别的,否则应使用其他强制转换运算符之一。 -* 允许将任何指针转换为任何其他指针类型(如 `char*` 到 `int*` 或 `One_class*` 到 `Unrelated_class*` 之类的转换,但其本身并不安全) -* 也允许将任何整数类型转换为任何指针类型以及反向转换。 -* reinterpret_cast 运算符不能丢掉 const、volatile 或 __unaligned 特性。 -* reinterpret_cast 的一个实际用途是在哈希函数中,即,通过让两个不同的值几乎不以相同的索引结尾的方式将值映射到索引。 +* 无编译时类型安全检查 +* 二进制位级重新解释 +* 最危险的转换操作符 + +| 转换类型 | 安全性 | 示例 | +|------------------------|--------------|-------------------------------| +| 指针↔指针 | ❌ 高危 | `MyClass* obj; void* p=reinterpret_cast(obj);` | +| 指针↔整型 | ❌ 高危 | `intptr_t addr=reinterpret_cast(&obj);` | +| 函数指针转换 | ❌ 极高危 | 不同签名函数指针转换 | +| 内存映射 I/O | ⚠️ 系统编程 | 硬件寄存器访问 | #### bad_cast -* 由于强制转换为引用类型失败,dynamic_cast 运算符引发 bad_cast 异常。 +* `dynamic_cast` 引用转换失败的异常类型。 bad_cast 使用 @@ -1142,10 +1167,6 @@ catch (bad_cast b) { ### 运行时类型信息 (RTTI) -#### dynamic_cast - -* 用于多态类型的转换 - #### typeid * typeid 运算符允许在运行时确定对象的类型 diff --git a/README_en.md b/README_en.md index b4a630b3..2811dc23 100644 --- a/README_en.md +++ b/README_en.md @@ -1102,37 +1102,62 @@ Deprecated by c ++ 11 due to lack of language features such as `std::move` seman #### static_cast -* For non-polymorphic conversions -* Do not perform runtime type checking (conversion security is not as good as dynamic_cast) -* Usually used to convert numeric data types (such as float-> int) -* You can move the pointer throughout the class hierarchy. It is safe (upward conversion) for a child class to be converted to a parent class, and it is not safe to convert a parent class to a child class (because a child class may have fields or methods that are not in the parent class) - -> Upcast is an implicit conversion. +* Compile-time type conversion (no runtime checks) +* Does not depend on RTTI + +| Conversion Type | Safety | Example | +|--------------------------|--------------|--------------------------| +| Numeric conversion | ✅ Safe | `float f=3.14; int i=static_cast(f);` | +| Upcast (class hierarchy) | ✅ Safe | `Derived* d; Base* b=static_cast(d);` | +| Downcast (class hierarchy)| ⚠️ Unsafe | `Base* b=new Base; Derived* d=static_cast(b);` | +| Same-type conversion | ✅ Safe | `MyClass* p; MyClass* same=static_cast(p);` | +| Explicit constructor call| ✅ Safe | `func(static_cast("text"));` | +| Any type→void* | ✅ Safe | `int* p; void* vp=static_cast(p);` | +| Enum↔Integer | ✅ Safe | `enum Color{RED}; int c=static_cast(RED);` | #### dynamic_cast -* For polymorphic type conversions -* Perform line runtime type checking -* Only applicable to pointers or references -* Conversion of ambiguous pointers will fail (return nullptr), but no exception will be thrown -* You can move the pointer throughout the class hierarchy, including up conversion, down conversion +* Runtime type checking (depends on RTTI) +* Requires polymorphic type (base must have at least one virtual function) +* Safe failure mechanism (nullptr or exception) + +| Conversion Type | Safety | Runtime Cost | Polymorphic Required | Failure Handling | Example | +|---------------------|--------|--------------|----------------------|---------------------------|---------| +| Upcast | ✅ Safe | None | ❌ Not required | Not applicable (always succeeds) | `Derived* d; Base* b = dynamic_cast(d);` | +| Downcast | ✅ Safe | Yes | ✅ Required | Pointer→`nullptr`
Reference→`std::bad_cast` | `Base* b; Derived* d = dynamic_cast(b);` | +| Cross-cast | ✅ Safe | Yes | ✅ Required | Pointer→`nullptr`
Reference→`std::bad_cast` | `B2* b2 = dynamic_cast(b1); // In diamond inheritance` | +| Same-type conversion| ✅ Safe | None | ❌ Not required | Not applicable (always succeeds) | `Derived* d2 = dynamic_cast(d1);` | +| Any type→void* | ✅ Safe | Yes | ✅ Required | `nullptr` | `void* p = dynamic_cast(obj);` | #### const_cast -* Used to remove const, volatile, and __unaligned features (such as converting const int to int) +* Compile-time type modifier operation +* Only modifies `const`/`volatile` attributes +* Does not change underlying binary representation + +| Conversion Type | Safety | Example | +|------------------------|--------------|----------------------------------| +| Remove const | ⚠️ Risky | `const int* cp; int* p=const_cast(cp);` | +| Remove volatile | ⚠️ Risky | `volatile int* vp; int* p=const_cast(vp);` | +| Add const | ✅ Safe | `int* p; const int* cp=const_cast(p);` | +| Legacy API compatibility | ⚠️ Necessary risk | `legacy_api(const_cast(str.c_str()));` | #### reinterpret_cast -* Simple reinterpretation for bits -* Misuse of the reinterpret_cast operator can be very risky. Unless the required conversion itself is low-level, you should use one of the other cast operators. -* Allows conversion of any pointer to any other pointer type (such as `char *` to `int *` or `One_class *` to `Unrelated_class *`, but it is not itself safe) -* Also allows conversion of any integer type to any pointer type and reverse conversion. -* The reinterpret_cast operator cannot lose const, volatile, or __unaligned attributes. -* A practical use of reinterpret_cast is in a hash function, which is to map values to indexes by making two different values hardly end with the same index. +* No compile-time type safety checks +* Binary bit-level reinterpretation +* Most dangerous cast operator + +| Conversion Type | Safety | Example | +|------------------------|--------------|----------------------------------| +| Pointer↔Pointer | ❌ High risk | `MyClass* obj; void* p=reinterpret_cast(obj);` | +| Pointer↔Integer | ❌ High risk | `intptr_t addr=reinterpret_cast(&obj);` | +| Function pointer conversion | ❌ Extreme risk | Converting function pointers with different signatures | +| Memory-mapped I/O | ⚠️ Systems programming | Hardware register access | #### bad_cast -* The dynamic_cast operator throws a bad_cast exception because the cast to a reference type fails. +* The exception type for a failed reference conversion using `dynamic_cast`. bad_cast demo @@ -1147,10 +1172,6 @@ catch (bad_cast b) { ### Runtime Type Information (RTTI) -#### dynamic_cast - -* For polymorphic type conversions - #### typeid * The typeid operator allows determining the type of an object at runtime From f7af99f12c0e204a96205825f3f190079980be54 Mon Sep 17 00:00:00 2001 From: huihut Date: Fri, 25 Jul 2025 20:45:01 +0800 Subject: [PATCH 09/20] fix Casting Operators https://github.com/huihut/interview/issues/113 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2373a616..87b2dd17 100644 --- a/README.md +++ b/README.md @@ -1102,7 +1102,7 @@ unique_ptr 是 C++11 才开始提供的类型,是一种在异常时可以帮 | 转换类型 | 安全性 | 示例 | |--------------------------|--------------|--------------------------| -| 数值类型转 | ✅ 安全 | `float f=3.14; int i=static_cast(f);` | +| 数值类型转换 | ✅ 安全 | `float f=3.14; int i=static_cast(f);` | | 类向上转换 | ✅ 安全 | `Derived* d; Base* b=static_cast(d);` | | 类向下转换 | ⚠️ 不安全 | `Base* b=new Base; Derived* d=static_cast(b);` | | 类不变转换 | ✅ 安全 | `MyClass* p; MyClass* same=static_cast(p);` | From 6fa52825716a50f6c959d4d342e613e3338e8f6e Mon Sep 17 00:00:00 2001 From: huihut Date: Fri, 25 Jul 2025 20:49:45 +0800 Subject: [PATCH 10/20] fix OSPF (Open Shortest Path First) https://github.com/huihut/interview/issues/101 --- README.md | 2 +- README_en.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 87b2dd17..ef23e191 100644 --- a/README.md +++ b/README.md @@ -2187,7 +2187,7 @@ ICMP 报文格式: #### 内部网关协议 * RIP(Routing Information Protocol,路由信息协议) -* OSPF(Open Sortest Path First,开放最短路径优先) +* OSPF(Open Shortest Path First,开放最短路径优先) #### 外部网关协议 diff --git a/README_en.md b/README_en.md index 2811dc23..623890e2 100644 --- a/README_en.md +++ b/README_en.md @@ -2186,7 +2186,7 @@ application: #### Interior Gateway Protocol * RIP (Routing Information Protocol, Routing Information Protocol) -* OSPF (Open Sortest Path First) +* OSPF (Open Shortest Path First) #### External gateway protocol From 8b25cc6dd86083a16aff9d1c1c83b19491f1503b Mon Sep 17 00:00:00 2001 From: huihut Date: Fri, 25 Jul 2025 22:51:43 +0800 Subject: [PATCH 11/20] =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=9C=9F=E6=9C=9F->?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/huihut/interview/issues/100 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ef23e191..c7cfac96 100644 --- a/README.md +++ b/README.md @@ -814,7 +814,7 @@ public: }; ``` -#### 动态多态(运行期期/晚绑定) +#### 动态多态(运行期/晚绑定) * 虚函数:用 virtual 修饰成员函数,使其成为虚函数 * 动态绑定:当使用基类的引用或指针调用一个虚函数时将发生动态绑定 From ae64f57d2e787306b03a9277aff6acb4a42dc656 Mon Sep 17 00:00:00 2001 From: huihut Date: Sat, 26 Jul 2025 00:19:46 +0800 Subject: [PATCH 12/20] fix typos https://github.com/huihut/interview/issues/91 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c7cfac96..9e1a6306 100644 --- a/README.md +++ b/README.md @@ -1078,7 +1078,7 @@ weak_ptr 允许你共享但不拥有某对象,一旦最末一个拥有该对 ##### unique_ptr -unique_ptr 是 C++11 才开始提供的类型,是一种在异常时可以帮助避免资源泄漏的智能指针。采用独占式拥有,意味着可以确保一个对象和其相应的资源同一时间只被一个 pointer 拥有。一旦拥有着被销毁或编程 empty,或开始拥有另一个对象,先前拥有的那个对象就会被销毁,其任何相应资源亦会被释放。 +unique_ptr 是 C++11 才开始提供的类型,是一种在异常时可以帮助避免资源泄漏的智能指针。采用独占式拥有,意味着可以确保一个对象和其相应的资源同一时间只被一个 pointer 拥有。一旦拥有者被销毁或变成空或开始拥有另一个对象,先前拥有的那个对象就会被销毁,其任何相应资源亦会被释放。 * unique_ptr 用于取代 auto_ptr From 358a4cbe713208210764625940ddaf65aa90a3c5 Mon Sep 17 00:00:00 2001 From: huihut Date: Sat, 26 Jul 2025 00:28:54 +0800 Subject: [PATCH 13/20] fix Simple Mail Transfer Protocol https://github.com/huihut/interview/issues/95 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e1a6306..c338f536 100644 --- a/README.md +++ b/README.md @@ -2486,7 +2486,7 @@ TRACE | 回显服务器收到的请求,主要用于测试或诊断 ##### 其他协议 -* SMTP(Simple Main Transfer Protocol,简单邮件传输协议)是在 Internet 传输 Email 的标准,是一个相对简单的基于文本的协议。在其之上指定了一条消息的一个或多个接收者(在大多数情况下被确认是存在的),然后消息文本会被传输。可以很简单地通过 Telnet 程序来测试一个 SMTP 服务器。SMTP 使用 TCP 端口 25。 +* SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)是在 Internet 传输 Email 的标准,是一个相对简单的基于文本的协议。在其之上指定了一条消息的一个或多个接收者(在大多数情况下被确认是存在的),然后消息文本会被传输。可以很简单地通过 Telnet 程序来测试一个 SMTP 服务器。SMTP 使用 TCP 端口 25。 * DHCP(Dynamic Host Configuration Protocol,动态主机设置协议)是一个局域网的网络协议,使用 UDP 协议工作,主要有两个用途: * 用于内部网络或网络服务供应商自动分配 IP 地址给用户 * 用于内部网络管理员作为对所有电脑作中央管理的手段 From 8871b8ffa81a9211e955ca45956cbbb0bf385370 Mon Sep 17 00:00:00 2001 From: huihut Date: Sat, 26 Jul 2025 00:56:55 +0800 Subject: [PATCH 14/20] fix Named pipes and Anonymous pipes https://github.com/huihut/interview/issues/96 --- README.md | 4 ++-- README_en.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c338f536..963b216e 100644 --- a/README.md +++ b/README.md @@ -1867,12 +1867,12 @@ B树/B+树 |O(log2n) | | #### 进程之间的通信方式以及优缺点 * 管道(PIPE) - * 有名管道:一种半双工的通信方式,它允许无亲缘关系进程间的通信 + * 有名管道(命名管道):一种先进先出的通信方式,它允许无亲缘关系进程间的通信 * 优点:可以实现任意关系的进程间的通信 * 缺点: 1. 长期存于系统中,使用不当容易出错 2. 缓冲区有限 - * 无名管道:一种半双工的通信方式,只能在具有亲缘关系的进程间使用(父子进程) + * 无名管道(匿名管道):一种单工先进先出的通信方式,只能在具有亲缘关系的进程间使用(父子进程) * 优点:简单方便 * 缺点: 1. 局限于单向通信 diff --git a/README_en.md b/README_en.md index 623890e2..cf3699dc 100644 --- a/README_en.md +++ b/README_en.md @@ -1866,12 +1866,12 @@ For non-threaded systems: #### Communication between processes and advantages and disadvantages * Pipeline (PIPE) - * Famous Pipeline: A half-duplex communication method that allows communication between unrelated processes + * Named pipes: A first-in-first-out communication method that allows communication between unrelated processes * Advantages: can achieve inter-process communication in any relationship * Disadvantages: 1. Long-term storage in the system, improper use is prone to errors Limited buffer - * Unnamed pipe: a half-duplex communication method that can only be used between processes with parental relationships (parent-child processes) + * Anonymous pipes: A simplex first-in-first-out communication method that can only be used between processes with affinity (parent-child processes) * Advantages: simple and convenient * Disadvantages: Limited to one-way communication From cb34d14bc7e22e63291c7395540347a5fc26d329 Mon Sep 17 00:00:00 2001 From: huihut Date: Sat, 26 Jul 2025 21:58:43 +0800 Subject: [PATCH 15/20] =?UTF-8?q?=E5=88=A0=E9=99=A4=EF=BC=9A=E5=A6=82?= =?UTF-8?q?=E4=BD=95=E5=AE=9A=E4=B9=89=E4=B8=80=E4=B8=AA=E5=8F=AA=E8=83=BD?= =?UTF-8?q?=E5=9C=A8=E5=A0=86=E4=B8=8A=EF=BC=88=E6=A0=88=E4=B8=8A=EF=BC=89?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=AF=B9=E8=B1=A1=E7=9A=84=E7=B1=BB=EF=BC=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/huihut/interview/issues/112 --- README.md | 16 ---------------- README_en.md | 16 ---------------- 2 files changed, 32 deletions(-) diff --git a/README.md b/README.md index 963b216e..92f615f2 100644 --- a/README.md +++ b/README.md @@ -1026,22 +1026,6 @@ new (place_address) type [size] { braced initializer list } 3. 必须保证成员函数的 `delete this ` 后面没有调用 this 了 4. 必须保证 `delete this` 后没有人使用了 -### 如何定义一个只能在堆上(栈上)生成对象的类? - -> [如何定义一个只能在堆上(栈上)生成对象的类?](https://www.nowcoder.com/questionTerminal/0a584aa13f804f3ea72b442a065a7618) - -#### 只能在堆上 - -方法:将析构函数设置为私有 - -原因:C++ 是静态绑定语言,编译器管理栈上对象的生命周期,编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性。若析构函数不可访问,则不能在栈上创建对象。 - -#### 只能在栈上 - -方法:将 new 和 delete 重载为私有 - -原因:在堆上生成对象,使用 new 关键词操作,其过程分为两阶段:第一阶段,使用 new 在堆上寻找可用内存,分配给对象;第二阶段,调用构造函数生成对象。将 new 操作设置为私有,那么第一阶段就无法完成,就不能够在堆上生成对象。 - ### 智能指针 #### C++ 标准库(STL)中 diff --git a/README_en.md b/README_en.md index cf3699dc..26dda640 100644 --- a/README_en.md +++ b/README_en.md @@ -1031,22 +1031,6 @@ Legal, but: 3. You must ensure that the member function does not call this after `delete this` 4. Make sure no one uses it after delete this -### How to define a class that can only generate objects on the heap (on the stack)? - -> [How to define a class that can only generate objects on the heap (on the stack)?](https://www.nowcoder.com/questionTerminal/0a584aa13f804f3ea72b442a065a7618) - -#### Only on the heap - -Method: Make the destructor private - -Reason: C ++ is a static binding language. The compiler manages the life cycle of objects on the stack. When the compiler allocates stack space for class objects, it first checks the accessibility of the class's destructor. If the destructor is not accessible, the object cannot be created on the stack. - -#### Only on the stack - -Method: overload new and delete as private - -Reason: The object is generated on the heap using the new keyword operation. The process is divided into two stages: the first stage uses new to find available memory on the heap and allocates it to the object; the second stage calls the constructor to generate the object. By setting the new operation to private, the first phase cannot be completed, and objects cannot be generated on the heap. - ### Smart pointer #### In the C ++ Standard Library (STL) From 48fd81d93b562df1c71e04e31110e8c69ddb4fdd Mon Sep 17 00:00:00 2001 From: huihut Date: Sat, 26 Jul 2025 23:21:52 +0800 Subject: [PATCH 16/20] =?UTF-8?q?=E7=BC=96=E8=AF=91=E5=99=A8=E6=89=A9?= =?UTF-8?q?=E5=B1=95=E4=B8=8E=E6=A0=87=E5=87=86=E5=AF=B9=E9=BD=90=E6=8E=A7?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/huihut/interview/issues/110 --- README.md | 41 ++++++++++++++++++++++++++++++----------- README_en.md | 45 +++++++++++++++++++++++++++++++++------------ 2 files changed, 63 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 92f615f2..a7f175cf 100644 --- a/README.md +++ b/README.md @@ -290,24 +290,43 @@ assert( p != NULL ); // assert 不可用 * sizeof 对数组,得到整个数组所占空间大小。 * sizeof 对指针,得到指针本身所占空间大小。 -### #pragma pack(n) +### 编译器扩展与标准对齐控制 -设定结构体、联合以及类成员变量以 n 字节方式对齐 +* 编译器扩展:`#pragma pack(n)`,将随后定义的 `struct`/`class`/`union` 的成员最大对齐限制为 n 字节。 +* 标准对齐控制: + * `alignas(k)`,要求类型或变量至少按 k 字节对齐(向上取整到 ≥ 自然对齐)。 + * `alignof(T)`,获取类型 T 的自然对齐要求(编译时常量)。 -#pragma pack(n) 使用 +特性 |#pragma pack|alignas +--------|--------------|------------ +标准化 |❌ 编译器扩展 | ✅ C++11标准 +对齐方向|⬇️ 只能减小对齐| ⬆️ 只能增大对齐 +可移植性|❌ 编译器依赖 | ✅ 跨平台 +作用范围|🔄 影响整个结构| 🎯 可针对单个成员 +性能影响|⚠️ 可能降低内存访问速度| ⚠️ 过度对齐浪费空间 + +使用 ```cpp -#pragma pack(push) // 保存对齐状态 -#pragma pack(4) // 设定为 4 字节对齐 +#include +#include -struct test -{ - char m1; - double m4; - int m3; +#pragma pack(push, 1) // 最大对齐 1 字节,紧凑布局 +struct PackedHeader { + uint16_t len; // offset 0 + uint32_t id; // offset 2 }; +#pragma pack(pop) -#pragma pack(pop) // 恢复对齐状态 +struct alignas(8) Align8 { + double value; // offset 0, 占 8 字节 + int flag; // offset 8 +}; + +int main() { + std::cout << "PackedHeader size: " << sizeof(PackedHeader) << "\n"; // 6 + std::cout << "Align8 size: " << sizeof(Align8) << "\n"; // 16 +} ``` ### 位域 diff --git a/README_en.md b/README_en.md index 26dda640..283488f1 100644 --- a/README_en.md +++ b/README_en.md @@ -295,25 +295,46 @@ assert( p != NULL ); // assert is not available * sizeof For arrays - get the size of the entire array. * sizeof For pointers - get the size of the space occupied by the pointer itself. -### #pragma pack(n) +### Compiler Extensions vs Standard Alignment Control -Set structure, union, and class member variables to be n-byte aligned +* Compiler Extension `#pragma pack(n)`, restricts the maximum alignment of members in subsequently defined `struct`/`class`/`union` to n bytes. +* Standard Alignment Control: + * `alignas(k)`, requires types or variables to be aligned to at least k bytes (rounds up to ≥ natural alignment). + * `alignof(T)`, gets the natural alignment requirement of type T (compile-time constant). -#pragma pack (n) use +Feature | `#pragma pack` | `alignas` +----------------|-------------------------|--------------------- +Standardization | ❌ Compiler Extension | ✅ C++11 Standard +Alignment Direction | ⬇️ Only decreases alignment | ⬆️ Only increases alignment +Portability | ❌ Compiler Dependent | ✅ Cross-platform +Scope | 🔄 Affects entire struct | 🎯 Per-member control +Performance Impact | ⚠️ May reduce memory access speed | ⚠️ Over-alignment wastes space + +#### Usage Examples ```cpp -#pragma pack(push) // save alignment state -#pragma pack(4) // Set to 4 byte alignment +#include +#include -struct test -{ - char m1; - double m4; - int m3; +#pragma pack(push, 1) // Max alignment 1 byte (compact layout) +struct PackedHeader { + uint16_t len; // offset 0 + uint32_t id; // offset 2 }; +#pragma pack(pop) -#pragma pack(pop) // Restore alignment -``` +struct alignas(8) Align8 { // Force 8-byte alignment + double value; // offset 0 (8 bytes) + int flag; // offset 8 +}; + +int main() { + std::cout << "PackedHeader size: " + << sizeof(PackedHeader) << "\n"; // Output: 6 + + std::cout << "Align8 size: " + << sizeof(Align8) << "\n"; // Output: 16 +} ### Bit field From 3ecb6a28aa8e80ece29ab41ae346594f822ce611 Mon Sep 17 00:00:00 2001 From: huihut Date: Sun, 27 Jul 2025 19:53:17 +0800 Subject: [PATCH 17/20] fix typeid https://github.com/huihut/interview/issues/12#issuecomment-860158224 --- README.md | 2 +- README_en.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a7f175cf..f0afc34d 100644 --- a/README.md +++ b/README.md @@ -1173,7 +1173,7 @@ catch (bad_cast b) { #### typeid * typeid 运算符允许在运行时确定对象的类型 -* type\_id 返回一个 type\_info 对象的引用 +* typeid 返回一个 type\_info 对象的引用 * 如果想通过基类的指针获得派生类的数据类型,基类必须带有虚函数 * 只能获取对象的实际类型 diff --git a/README_en.md b/README_en.md index 283488f1..3429f318 100644 --- a/README_en.md +++ b/README_en.md @@ -1180,7 +1180,7 @@ catch (bad_cast b) { #### typeid * The typeid operator allows determining the type of an object at runtime -* type \ _id returns a reference to a type \ _info object +* typeid returns a reference to a type\_info object * If you want to get the data type of the derived class through the pointer of the base class, the base class must have a virtual function * Can only get the actual type of the object From eda93dba0b5dd1100b8c46cae5e81502eebe72ec Mon Sep 17 00:00:00 2001 From: huihut Date: Sun, 27 Jul 2025 20:00:38 +0800 Subject: [PATCH 18/20] =?UTF-8?q?TCP=20=E7=AB=AF=E5=88=B0=E7=AB=AF?= =?UTF-8?q?=E9=80=9A=E4=BF=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/huihut/interview/issues/12#issuecomment-1003025043 --- README.md | 2 +- README_en.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f0afc34d..0756970e 100644 --- a/README.md +++ b/README.md @@ -2237,7 +2237,7 @@ ICMP 报文格式: 特征: * 面向连接 -* 只能点对点(一对一)通信 +* 端到端通信 * 可靠交互 * 全双工通信 * 面向字节流 diff --git a/README_en.md b/README_en.md index 3429f318..e2cf16e0 100644 --- a/README_en.md +++ b/README_en.md @@ -2238,7 +2238,7 @@ Port number | 21 | 23 | 25 | 53 | 69 | 80 | 443 | 161 Feature: * Connection oriented -* Only point-to-point (one-to-one) communication +* End-to-end communication * Reliable interaction * Full-duplex communication * Byte stream oriented From c3afca8f525a068303982223173b7d8a4dc64b42 Mon Sep 17 00:00:00 2001 From: huihut Date: Sun, 27 Jul 2025 20:36:24 +0800 Subject: [PATCH 19/20] update docsify --- docs/README.md | 325 ++++++++++++++++++++++++++---------------------- docs/en.md | 330 +++++++++++++++++++++++++++---------------------- 2 files changed, 353 insertions(+), 302 deletions(-) diff --git a/docs/README.md b/docs/README.md index 1f678524..23ae4209 100644 --- a/docs/README.md +++ b/docs/README.md @@ -220,37 +220,37 @@ using namespace std; class Base { public: - inline virtual void who() - { - cout << "I am Base\n"; - } - virtual ~Base() {} + inline virtual void who() + { + cout << "I am Base\n"; + } + virtual ~Base() {} }; class Derived : public Base { public: - inline void who() // 不写inline时隐式内联 - { - cout << "I am Derived\n"; - } + inline void who() // 不写inline时隐式内联 + { + cout << "I am Derived\n"; + } }; int main() { - // 此处的虚函数 who(),是通过类(Base)的具体对象(b)来调用的,编译期间就能确定了,所以它可以是内联的,但最终是否内联取决于编译器。 - Base b; - b.who(); + // 此处的虚函数 who(),是通过类(Base)的具体对象(b)来调用的,编译期间就能确定了,所以它可以是内联的,但最终是否内联取决于编译器。 + Base b; + b.who(); - // 此处的虚函数是通过指针调用的,呈现多态性,需要在运行时期间才能确定,所以不能为内联。 - Base *ptr = new Derived(); - ptr->who(); + // 此处的虚函数是通过指针调用的,呈现多态性,需要在运行时期间才能确定,所以不能为内联。 + Base *ptr = new Derived(); + ptr->who(); - // 因为Base有虚析构函数(virtual ~Base() {}),所以 delete 时,会先调用派生类(Derived)析构函数,再调用基类(Base)析构函数,防止内存泄漏。 - delete ptr; - ptr = nullptr; + // 因为Base有虚析构函数(virtual ~Base() {}),所以 delete 时,会先调用派生类(Derived)析构函数,再调用基类(Base)析构函数,防止内存泄漏。 + delete ptr; + ptr = nullptr; - system("pause"); - return 0; + system("pause"); + return 0; } ``` @@ -283,24 +283,43 @@ assert( p != NULL ); // assert 不可用 * sizeof 对数组,得到整个数组所占空间大小。 * sizeof 对指针,得到指针本身所占空间大小。 -### #pragma pack(n) +### 编译器扩展与标准对齐控制 -设定结构体、联合以及类成员变量以 n 字节方式对齐 +* 编译器扩展:`#pragma pack(n)`,将随后定义的 `struct`/`class`/`union` 的成员最大对齐限制为 n 字节。 +* 标准对齐控制: + * `alignas(k)`,要求类型或变量至少按 k 字节对齐(向上取整到 ≥ 自然对齐)。 + * `alignof(T)`,获取类型 T 的自然对齐要求(编译时常量)。 -#pragma pack(n) 使用 +特性 |#pragma pack|alignas +--------|--------------|------------ +标准化 |❌ 编译器扩展 | ✅ C++11标准 +对齐方向|⬇️ 只能减小对齐| ⬆️ 只能增大对齐 +可移植性|❌ 编译器依赖 | ✅ 跨平台 +作用范围|🔄 影响整个结构| 🎯 可针对单个成员 +性能影响|⚠️ 可能降低内存访问速度| ⚠️ 过度对齐浪费空间 + +使用 ```cpp -#pragma pack(push) // 保存对齐状态 -#pragma pack(4) // 设定为 4 字节对齐 +#include +#include -struct test -{ - char m1; - double m4; - int m3; +#pragma pack(push, 1) // 最大对齐 1 字节,紧凑布局 +struct PackedHeader { + uint16_t len; // offset 0 + uint32_t id; // offset 2 }; +#pragma pack(pop) -#pragma pack(pop) // 恢复对齐状态 +struct alignas(8) Align8 { + double value; // offset 0, 占 8 字节 + int flag; // offset 8 +}; + +int main() { + std::cout << "PackedHeader size: " << sizeof(PackedHeader) << "\n"; // 6 + std::cout << "Align8 size: " << sizeof(Align8) << "\n"; // 16 +} ``` ### 位域 @@ -315,14 +334,14 @@ Bit mode: 2; // mode 占 2 位 * 位域的类型必须是整型或枚举类型,带符号类型中的位域的行为将因具体实现而定 * 取地址运算符(&)不能作用于位域,任何指针都无法指向类的位域 -### extern "C" - -* 被 extern 限定的函数或变量是 extern 类型的 -* 被 `extern "C"` 修饰的变量和函数是按照 C 语言方式编译和链接的 +### extern 与 extern "C" -`extern "C"` 的作用是让 C++ 编译器将 `extern "C"` 声明的代码当作 C 语言代码处理,可以避免 C++ 因符号修饰导致代码不能和C语言库中的符号进行链接的问题。 +* `extern` 是存储类说明符(storage-class-specifier),用于声明变量或函数具有外部链接,表示实体的定义可能在其他翻译单元中。 +* `extern "C"` 是链接指示(linkage directive),它指定函数或变量使用 C 语言链接(不影响编译规则)。 + 1. 禁止 C++ 名称修饰。确保符号名称与该平台下 C 编译器生成的名称一致,避免链接时因名称修饰导致的未定义符号错误,但不保证平台 ABI(应用二进制接口)一致性。 + 2. 实现 C/C++ 互操作。允许 C++ 函数被 C 代码调用(或反之)。 -extern "C" 使用 +`extern "C"` 使用 ```cpp #ifdef __cplusplus @@ -476,14 +495,14 @@ explicit 使用 ```cpp struct A { - A(int) { } - operator bool() const { return true; } + A(int) { } + operator bool() const { return true; } }; struct B { - explicit B(int) {} - explicit operator bool() const { return true; } + explicit B(int) {} + explicit operator bool() const { return true; } }; void doA(A a) {} @@ -492,29 +511,29 @@ void doB(B b) {} int main() { - A a1(1); // OK:直接初始化 - A a2 = 1; // OK:复制初始化 - A a3{ 1 }; // OK:直接列表初始化 - A a4 = { 1 }; // OK:复制列表初始化 - A a5 = (A)1; // OK:允许 static_cast 的显式转换 - doA(1); // OK:允许从 int 到 A 的隐式转换 - if (a1); // OK:使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换 - bool a6(a1); // OK:使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换 - bool a7 = a1; // OK:使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换 - bool a8 = static_cast(a1); // OK :static_cast 进行直接初始化 - - B b1(1); // OK:直接初始化 - B b2 = 1; // 错误:被 explicit 修饰构造函数的对象不可以复制初始化 - B b3{ 1 }; // OK:直接列表初始化 - B b4 = { 1 }; // 错误:被 explicit 修饰构造函数的对象不可以复制列表初始化 - B b5 = (B)1; // OK:允许 static_cast 的显式转换 - doB(1); // 错误:被 explicit 修饰构造函数的对象不可以从 int 到 B 的隐式转换 - if (b1); // OK:被 explicit 修饰转换函数 B::operator bool() 的对象可以从 B 到 bool 的按语境转换 - bool b6(b1); // OK:被 explicit 修饰转换函数 B::operator bool() 的对象可以从 B 到 bool 的按语境转换 - bool b7 = b1; // 错误:被 explicit 修饰转换函数 B::operator bool() 的对象不可以隐式转换 - bool b8 = static_cast(b1); // OK:static_cast 进行直接初始化 - - return 0; + A a1(1); // OK:直接初始化 + A a2 = 1; // OK:复制初始化 + A a3{ 1 }; // OK:直接列表初始化 + A a4 = { 1 }; // OK:复制列表初始化 + A a5 = (A)1; // OK:允许 static_cast 的显式转换 + doA(1); // OK:允许从 int 到 A 的隐式转换 + if (a1); // OK:使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换 + bool a6(a1); // OK:使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换 + bool a7 = a1; // OK:使用转换函数 A::operator bool() 的从 A 到 bool 的隐式转换 + bool a8 = static_cast(a1); // OK :static_cast 进行直接初始化 + + B b1(1); // OK:直接初始化 + B b2 = 1; // 错误:被 explicit 修饰构造函数的对象不可以复制初始化 + B b3{ 1 }; // OK:直接列表初始化 + B b4 = { 1 }; // 错误:被 explicit 修饰构造函数的对象不可以复制列表初始化 + B b5 = (B)1; // OK:允许 static_cast 的显式转换 + doB(1); // 错误:被 explicit 修饰构造函数的对象不可以从 int 到 B 的隐式转换 + if (b1); // OK:被 explicit 修饰转换函数 B::operator bool() 的对象可以从 B 到 bool 的按语境转换 + bool b6(b1); // OK:被 explicit 修饰转换函数 B::operator bool() 的对象可以从 B 到 bool 的按语境转换 + bool b7 = b1; // 错误:被 explicit 修饰转换函数 B::operator bool() 的对象不可以隐式转换 + bool b8 = static_cast(b1); // OK:static_cast 进行直接初始化 + + return 0; } ``` @@ -559,7 +578,7 @@ Derived(parms) : Base(args) { } `using 指示` 使得某个特定命名空间中所有名字都可见,这样我们就无需再为它们添加任何前缀限定符了。如: ```cpp -using namespace_name name; +using namespace namespace_name; ``` #### 尽量少使用 `using 指示` 污染命名空间 @@ -608,24 +627,24 @@ int count = 11; // 全局(::)的 count class A { public: - static int count; // 类 A 的 count(A::count) + static int count; // 类 A 的 count(A::count) }; int A::count = 21; void fun() { - int count = 31; // 初始化局部的 count 为 31 - count = 32; // 设置局部的 count 的值为 32 + int count = 31; // 初始化局部的 count 为 31 + count = 32; // 设置局部的 count 的值为 32 } int main() { - ::count = 12; // 测试 1:设置全局的 count 的值为 12 + ::count = 12; // 测试 1:设置全局的 count 的值为 12 - A::count = 22; // 测试 2:设置类 A 的 count 为 22 + A::count = 22; // 测试 2:设置类 A 的 count 为 22 - fun(); // 测试 3 + fun(); // 测试 3 - return 0; + return 0; } ``` @@ -807,7 +826,7 @@ public: }; ``` -#### 动态多态(运行期期/晚绑定) +#### 动态多态(运行期/晚绑定) * 虚函数:用 virtual 修饰成员函数,使其成为虚函数 * 动态绑定:当使用基类的引用或指针调用一个虚函数时将发生动态绑定 @@ -931,9 +950,9 @@ virtual int A() = 0; * 虚函数不占用存储空间 * 虚函数表存储的是虚函数地址 -### 模板类、成员模板、虚函数 +### 类模板、成员模板、虚函数 -* 模板类中可以使用虚函数 +* 类模板中可以使用虚函数 * 一个类(无论是普通类还是类模板)的成员模板(本身是模板的成员函数)不能是虚函数 ### 抽象类、接口类、聚合类 @@ -1019,22 +1038,6 @@ new (place_address) type [size] { braced initializer list } 3. 必须保证成员函数的 `delete this ` 后面没有调用 this 了 4. 必须保证 `delete this` 后没有人使用了 -### 如何定义一个只能在堆上(栈上)生成对象的类? - -> [如何定义一个只能在堆上(栈上)生成对象的类?](https://www.nowcoder.com/questionTerminal/0a584aa13f804f3ea72b442a065a7618) - -#### 只能在堆上 - -方法:将析构函数设置为私有 - -原因:C++ 是静态绑定语言,编译器管理栈上对象的生命周期,编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性。若析构函数不可访问,则不能在栈上创建对象。 - -#### 只能在栈上 - -方法:将 new 和 delete 重载为私有 - -原因:在堆上生成对象,使用 new 关键词操作,其过程分为两阶段:第一阶段,使用 new 在堆上寻找可用内存,分配给对象;第二阶段,调用构造函数生成对象。将 new 操作设置为私有,那么第一阶段就无法完成,就不能够在堆上生成对象。 - ### 智能指针 #### C++ 标准库(STL)中 @@ -1071,7 +1074,7 @@ weak_ptr 允许你共享但不拥有某对象,一旦最末一个拥有该对 ##### unique_ptr -unique_ptr 是 C++11 才开始提供的类型,是一种在异常时可以帮助避免资源泄漏的智能指针。采用独占式拥有,意味着可以确保一个对象和其相应的资源同一时间只被一个 pointer 拥有。一旦拥有着被销毁或编程 empty,或开始拥有另一个对象,先前拥有的那个对象就会被销毁,其任何相应资源亦会被释放。 +unique_ptr 是 C++11 才开始提供的类型,是一种在异常时可以帮助避免资源泄漏的智能指针。采用独占式拥有,意味着可以确保一个对象和其相应的资源同一时间只被一个 pointer 拥有。一旦拥有者被销毁或变成空或开始拥有另一个对象,先前拥有的那个对象就会被销毁,其任何相应资源亦会被释放。 * unique_ptr 用于取代 auto_ptr @@ -1090,37 +1093,62 @@ unique_ptr 是 C++11 才开始提供的类型,是一种在异常时可以帮 #### static_cast -* 用于非多态类型的转换 -* 不执行运行时类型检查(转换安全性不如 dynamic_cast) -* 通常用于转换数值数据类型(如 float -> int) -* 可以在整个类层次结构中移动指针,子类转化为父类安全(向上转换),父类转化为子类不安全(因为子类可能有不在父类的字段或方法) +* 编译时类型转换(无运行时检查) +* 不依赖 RTTI -> 向上转换是一种隐式转换。 +| 转换类型 | 安全性 | 示例 | +|--------------------------|--------------|--------------------------| +| 数值类型转换 | ✅ 安全 | `float f=3.14; int i=static_cast(f);` | +| 类向上转换 | ✅ 安全 | `Derived* d; Base* b=static_cast(d);` | +| 类向下转换 | ⚠️ 不安全 | `Base* b=new Base; Derived* d=static_cast(b);` | +| 类不变转换 | ✅ 安全 | `MyClass* p; MyClass* same=static_cast(p);` | +| 显式构造函数调用 | ✅ 安全 | `func(static_cast("text"));` | +| 任意→void* | ✅ 安全 | `int* p; void* vp=static_cast(p);` | +| 枚举↔整型 | ✅ 安全 | `enum Color{RED}; int c=static_cast(RED);` | #### dynamic_cast -* 用于多态类型的转换 -* 执行行运行时类型检查 -* 只适用于指针或引用 -* 对不明确的指针的转换将失败(返回 nullptr),但不引发异常 -* 可以在整个类层次结构中移动指针,包括向上转换、向下转换 +* 运行时类型检查(依赖 RTTI) +* 多态类型要求(基类需至少一个虚函数) +* 安全失败机制(nullptr 或异常) + +| 转换类型 | 安全性 | 运行时开销 | 多态要求 | 失败处理 | 示例 | +|--------------|--------|------------|----------|------------------------|------| +| 类向上转换 | ✅ 安全 | 无 | ❌ 不需要 | 不适用(总是成功) | `Derived* d; Base* b = dynamic_cast(d);` | +| 类向下转换 | ✅ 安全 | 有 | ✅ 需要 | 指针→`nullptr`
引用→`std::bad_cast` | `Base* b=new Base; Derived* d = dynamic_cast(b);` | +| 类旁支转换 | ✅ 安全 | 有 | ✅ 需要 | 指针→`nullptr`
引用→`std::bad_cast` | `B2* b2 = dynamic_cast(b1); // 菱形继承中 B1*→B2*` | +| 类不变转换 | ✅ 安全 | 无 | ❌ 不需要 | 不适用(总是成功) | `Derived* d2 = dynamic_cast(d1);` | +| 任意→void* | ✅ 安全 | 有 | ✅ 需要 | `nullptr` | `void* p = dynamic_cast(obj);` | -#### const_cast +#### const_cast -* 用于删除 const、volatile 和 __unaligned 特性(如将 const int 类型转换为 int 类型 ) +* 编译时类型修饰符操作 +* 仅修改 `const`/`volatile` 属性 +* 不改变底层二进制表示 + +| 转换类型 | 安全性 | 示例 | +|------------------------|--------------|-------------------------------| +| 移除 const | ⚠️ 风险 | `const int* cp; int* p=const_cast(cp);` | +| 移除 volatile | ⚠️ 风险 | `volatile int* vp; int* p=const_cast(vp);` | +| 添加 const | ✅ 安全 | `int* p; const int* cp=const_cast(p);` | +| 兼容旧式 API | ⚠️ 必要风险 | `legacy_api(const_cast(str.c_str()));` | #### reinterpret_cast -* 用于位的简单重新解释 -* 滥用 reinterpret_cast 运算符可能很容易带来风险。 除非所需转换本身是低级别的,否则应使用其他强制转换运算符之一。 -* 允许将任何指针转换为任何其他指针类型(如 `char*` 到 `int*` 或 `One_class*` 到 `Unrelated_class*` 之类的转换,但其本身并不安全) -* 也允许将任何整数类型转换为任何指针类型以及反向转换。 -* reinterpret_cast 运算符不能丢掉 const、volatile 或 __unaligned 特性。 -* reinterpret_cast 的一个实际用途是在哈希函数中,即,通过让两个不同的值几乎不以相同的索引结尾的方式将值映射到索引。 +* 无编译时类型安全检查 +* 二进制位级重新解释 +* 最危险的转换操作符 + +| 转换类型 | 安全性 | 示例 | +|------------------------|--------------|-------------------------------| +| 指针↔指针 | ❌ 高危 | `MyClass* obj; void* p=reinterpret_cast(obj);` | +| 指针↔整型 | ❌ 高危 | `intptr_t addr=reinterpret_cast(&obj);` | +| 函数指针转换 | ❌ 极高危 | 不同签名函数指针转换 | +| 内存映射 I/O | ⚠️ 系统编程 | 硬件寄存器访问 | #### bad_cast -* 由于强制转换为引用类型失败,dynamic_cast 运算符引发 bad_cast 异常。 +* `dynamic_cast` 引用转换失败的异常类型。 bad_cast 使用 @@ -1135,14 +1163,10 @@ catch (bad_cast b) { ### 运行时类型信息 (RTTI) -#### dynamic_cast - -* 用于多态类型的转换 - #### typeid * typeid 运算符允许在运行时确定对象的类型 -* type\_id 返回一个 type\_info 对象的引用 +* typeid 返回一个 type\_info 对象的引用 * 如果想通过基类的指针获得派生类的数据类型,基类必须带有虚函数 * 只能获取对象的实际类型 @@ -1207,11 +1231,11 @@ void doSomething(Flyable *obj) // 做些事情 } int main(){ - Bird *b = new Bird(); - doSomething(b); - delete b; - b = nullptr; - return 0; + Bird *b = new Bird(); + doSomething(b); + delete b; + b = nullptr; + return 0; } ``` @@ -1359,10 +1383,10 @@ int main(){ ```cpp typedef struct { - ElemType *elem; - int top; - int size; - int increment; + ElemType *elem; + int top; + int size; + int increment; } SqStack; ``` @@ -1374,10 +1398,10 @@ typedef struct { ```cpp typedef struct { - ElemType * elem; - int front; - int rear; - int maxSize; + ElemType * elem; + int front; + int rear; + int maxSize; }SqQueue; ``` @@ -1405,10 +1429,10 @@ typedef struct { ```cpp typedef struct { - ElemType *elem; - int length; - int size; - int increment; + ElemType *elem; + int length; + int size; + int increment; } SqList; ``` @@ -1488,14 +1512,14 @@ typedef struct LNode { typedef char KeyType; typedef struct { - KeyType key; + KeyType key; }RcdType; typedef struct { - RcdType *rcd; - int size; - int count; - bool *tag; + RcdType *rcd; + int size; + int count; + bool *tag; }HashTable; ``` @@ -1839,12 +1863,12 @@ B树/B+树 |O(log2n) | | #### 进程之间的通信方式以及优缺点 * 管道(PIPE) - * 有名管道:一种半双工的通信方式,它允许无亲缘关系进程间的通信 + * 有名管道(命名管道):一种先进先出的通信方式,它允许无亲缘关系进程间的通信 * 优点:可以实现任意关系的进程间的通信 * 缺点: 1. 长期存于系统中,使用不当容易出错 2. 缓冲区有限 - * 无名管道:一种半双工的通信方式,只能在具有亲缘关系的进程间使用(父子进程) + * 无名管道(匿名管道):一种单工先进先出的通信方式,只能在具有亲缘关系的进程间使用(父子进程) * 优点:简单方便 * 缺点: 1. 局限于单向通信 @@ -2013,14 +2037,14 @@ using namespace std; int main() { - int i = 0x12345678; + int i = 0x12345678; - if (*((char*)&i) == 0x12) - cout << "大端" << endl; - else - cout << "小端" << endl; + if (*((char*)&i) == 0x12) + cout << "大端" << endl; + else + cout << "小端" << endl; - return 0; + return 0; } ``` @@ -2159,7 +2183,7 @@ ICMP 报文格式: #### 内部网关协议 * RIP(Routing Information Protocol,路由信息协议) -* OSPF(Open Sortest Path First,开放最短路径优先) +* OSPF(Open Shortest Path First,开放最短路径优先) #### 外部网关协议 @@ -2206,7 +2230,7 @@ ICMP 报文格式: 特征: * 面向连接 -* 只能点对点(一对一)通信 +* 端到端通信 * 可靠交互 * 全双工通信 * 面向字节流 @@ -2458,7 +2482,7 @@ TRACE | 回显服务器收到的请求,主要用于测试或诊断 ##### 其他协议 -* SMTP(Simple Main Transfer Protocol,简单邮件传输协议)是在 Internet 传输 Email 的标准,是一个相对简单的基于文本的协议。在其之上指定了一条消息的一个或多个接收者(在大多数情况下被确认是存在的),然后消息文本会被传输。可以很简单地通过 Telnet 程序来测试一个 SMTP 服务器。SMTP 使用 TCP 端口 25。 +* SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)是在 Internet 传输 Email 的标准,是一个相对简单的基于文本的协议。在其之上指定了一条消息的一个或多个接收者(在大多数情况下被确认是存在的),然后消息文本会被传输。可以很简单地通过 Telnet 程序来测试一个 SMTP 服务器。SMTP 使用 TCP 端口 25。 * DHCP(Dynamic Host Configuration Protocol,动态主机设置协议)是一个局域网的网络协议,使用 UDP 协议工作,主要有两个用途: * 用于内部网络或网络服务供应商自动分配 IP 地址给用户 * 用于内部网络管理员作为对所有电脑作中央管理的手段 @@ -3431,5 +3455,4 @@ int main( void ) 本仓库遵循 CC BY-NC-SA 4.0(署名 - 非商业性使用 - 相同方式共享) 协议,转载请注明出处,不得用于商业目的。 -[![CC BY-NC-SA 4.0](https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png)](https://github.com/huihut/interview/blob/master/LICENSE) - +[![CC BY-NC-SA 4.0](https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png)](https://github.com/huihut/interview/blob/master/LICENSE) \ No newline at end of file diff --git a/docs/en.md b/docs/en.md index 4b4c175b..2da8cf94 100644 --- a/docs/en.md +++ b/docs/en.md @@ -225,37 +225,37 @@ using namespace std; class Base { public: - inline virtual void who() - { - cout << "I am Base\n"; - } - virtual ~Base() {} + inline virtual void who() + { + cout << "I am Base\n"; + } + virtual ~Base() {} }; class Derived : public Base { public: - inline void who() // Implicit inlining when not writing inline - { - cout << "I am Derived\n"; - } + inline void who() // Implicit inlining when not writing inline + { + cout << "I am Derived\n"; + } }; int main() { - // The virtual function who () here is called through the concrete object (b) of the class (Base), which can be determined during compilation, so it can be inlined, but whether it is inlined depends on the compilation Device. - Base b; - b.who(); + // The virtual function who () here is called through the concrete object (b) of the class (Base), which can be determined during compilation, so it can be inlined, but whether it is inlined depends on the compilation Device. + Base b; + b.who(); - // The virtual function here is called through a pointer, which is polymorphic and needs to be determined during runtime, so it cannot be inlined. - Base *ptr = new Derived(); - ptr->who(); + // The virtual function here is called through a pointer, which is polymorphic and needs to be determined during runtime, so it cannot be inlined. + Base *ptr = new Derived(); + ptr->who(); - // Because Base has a virtual destructor (virtual ~ Base () {}), when deleting, the Derived destructor is called first, and then the Base destructor is called to prevent memory leaks. - delete ptr; - ptr = nullptr; + // Because Base has a virtual destructor (virtual ~ Base () {}), when deleting, the Derived destructor is called first, and then the Base destructor is called to prevent memory leaks. + delete ptr; + ptr = nullptr; - system("pause"); - return 0; + system("pause"); + return 0; } ``` @@ -288,25 +288,46 @@ assert( p != NULL ); // assert is not available * sizeof For arrays - get the size of the entire array. * sizeof For pointers - get the size of the space occupied by the pointer itself. -### #pragma pack(n) +### Compiler Extensions vs Standard Alignment Control -Set structure, union, and class member variables to be n-byte aligned +* Compiler Extension `#pragma pack(n)`, restricts the maximum alignment of members in subsequently defined `struct`/`class`/`union` to n bytes. +* Standard Alignment Control: + * `alignas(k)`, requires types or variables to be aligned to at least k bytes (rounds up to ≥ natural alignment). + * `alignof(T)`, gets the natural alignment requirement of type T (compile-time constant). -#pragma pack (n) use +Feature | `#pragma pack` | `alignas` +----------------|-------------------------|--------------------- +Standardization | ❌ Compiler Extension | ✅ C++11 Standard +Alignment Direction | ⬇️ Only decreases alignment | ⬆️ Only increases alignment +Portability | ❌ Compiler Dependent | ✅ Cross-platform +Scope | 🔄 Affects entire struct | 🎯 Per-member control +Performance Impact | ⚠️ May reduce memory access speed | ⚠️ Over-alignment wastes space + +#### Usage Examples ```cpp -#pragma pack(push) // save alignment state -#pragma pack(4) // Set to 4 byte alignment +#include +#include -struct test -{ - char m1; - double m4; - int m3; +#pragma pack(push, 1) // Max alignment 1 byte (compact layout) +struct PackedHeader { + uint16_t len; // offset 0 + uint32_t id; // offset 2 }; +#pragma pack(pop) -#pragma pack(pop) // Restore alignment -``` +struct alignas(8) Align8 { // Force 8-byte alignment + double value; // offset 0 (8 bytes) + int flag; // offset 8 +}; + +int main() { + std::cout << "PackedHeader size: " + << sizeof(PackedHeader) << "\n"; // Output: 6 + + std::cout << "Align8 size: " + << sizeof(Align8) << "\n"; // Output: 16 +} ### Bit field @@ -320,14 +341,14 @@ A class can define its (non-static) data members as bit-fields, which contain a * The type of the bit field must be an integer or enumerated type. The behavior of the bit field in a signed type will depend on the implementation. * The fetch operator (&) cannot be applied to the bit field, and no pointer can point to the bit field of the class -### extern "C" - -* Extern-qualified functions or variables are of type extern -* Variables and functions decorated with `extern" C "` are compiled and linked in C +### `extern` vs `extern "C"` -The function of `extern" C "` is to let the C ++ compiler treat the code declared by `extern" C "` as C language code, which can avoid the problem that the code cannot be linked with the symbols in the C language library due to symbol modification. . +* `extern` is a **storage-class specifier** used to declare that a variable or function has **external linkage**, indicating that the entity's definition may reside in another translation unit. +* `extern "C"` is a **linkage directive** that specifies functions or variables should use **C language linkage** (without affecting compilation rules). + 1. **Suppresses C++ name mangling**: Ensures symbol names match those generated by the C compiler _on that specific platform_, preventing undefined symbol errors during linking due to name decoration. **Does not guarantee platform ABI (Application Binary Interface) consistency**. + 2. **Enables C/C++ interoperability**: Allows C++ functions to be called from C code (and vice versa). -extern "C" demo +`extern "C"` demo ```cpp #ifdef __cplusplus @@ -480,14 +501,14 @@ explicit demo ```cpp struct A { - A(int) { } - operator bool() const { return true; } + A(int) { } + operator bool() const { return true; } }; struct B { - explicit B(int) {} - explicit operator bool() const { return true; } + explicit B(int) {} + explicit operator bool() const { return true; } }; void doA(A a) {} @@ -496,29 +517,29 @@ void doB(B b) {} int main() { - A a1(1); // OK:direct initialization - A a2 = 1; // OK:copy initialization - A a3{ 1 }; // OK:direct list initialization - A a4 = { 1 }; // OK:copy list initialization - A a5 = (A)1; // OK:Allow explicit conversion of static_cast - doA(1); // OK:Allow implicit conversion from int to A - if (a1); // OK: implicit conversion from A to bool using conversion function A ::operator bool() - bool a6(a1); // OK: implicit conversion from A to bool using conversion function A::operator bool() - bool a7 = a1; // OK: implicit conversion from A to bool using conversion function A::operator bool() - bool a8 = static_cast(a1); // OK: static_cast for direct initialization - - B b1(1); // OK:direct initialization - B b2 = 1; // Error: Object modified by explicit constructor cannot be initialized by copying - B b3{ 1 }; // OK:direct list initialization - B b4 = { 1 }; // Error: Object modified by explicit constructor cannot copy list initialization - B b5 = (B)1; // OK: Allow explicit conversion of static_cast - doB(1); // Error: Objects whose constructor is explicitly modified cannot be implicitly converted from int to B - if (b1); // OK: objects modified by explicit conversion function B::operator bool() can be converted from B to bool by context - bool b6(b1); // OK: Explicitly modified conversion function B::operator The object of bool() can be converted from B to bool by context - bool b7 = b1; // Error: Objects modified by explicit conversion function B :: operator bool () cannot be implicitly converted - bool b8 = static_cast(b1); // OK: static_cast performs direct initialization - - return 0; + A a1(1); // OK:direct initialization + A a2 = 1; // OK:copy initialization + A a3{ 1 }; // OK:direct list initialization + A a4 = { 1 }; // OK:copy list initialization + A a5 = (A)1; // OK:Allow explicit conversion of static_cast + doA(1); // OK:Allow implicit conversion from int to A + if (a1); // OK: implicit conversion from A to bool using conversion function A ::operator bool() + bool a6(a1); // OK: implicit conversion from A to bool using conversion function A::operator bool() + bool a7 = a1; // OK: implicit conversion from A to bool using conversion function A::operator bool() + bool a8 = static_cast(a1); // OK: static_cast for direct initialization + + B b1(1); // OK:direct initialization + B b2 = 1; // Error: Object modified by explicit constructor cannot be initialized by copying + B b3{ 1 }; // OK:direct list initialization + B b4 = { 1 }; // Error: Object modified by explicit constructor cannot copy list initialization + B b5 = (B)1; // OK: Allow explicit conversion of static_cast + doB(1); // Error: Objects whose constructor is explicitly modified cannot be implicitly converted from int to B + if (b1); // OK: objects modified by explicit conversion function B::operator bool() can be converted from B to bool by context + bool b6(b1); // OK: Explicitly modified conversion function B::operator The object of bool() can be converted from B to bool by context + bool b7 = b1; // Error: Objects modified by explicit conversion function B :: operator bool () cannot be implicitly converted + bool b8 = static_cast(b1); // OK: static_cast performs direct initialization + + return 0; } ``` @@ -537,7 +558,7 @@ int main() A `using declaration` introduces only one member of a namespace at a time. It allows us to know exactly which name is referenced in the program. Such as: ```cpp -using namespace_name :: name; +using namespace_name::name; ``` #### Using declaration of constructor @@ -563,7 +584,7 @@ Derived (parms): Base (args) {} The `using directive` makes all names in a particular namespace visible, so we don't need to add any prefix qualifiers to them. Such as: ```cpp -using namespace_name name; +using namespace namespace_name; ``` #### Minimize `using directives` to pollute namespaces @@ -612,24 +633,24 @@ int count = 11; // Global (: :) count class A { public: - static int count; // Count (A::count) of class A + static int count; // Count (A::count) of class A }; int A::count = 21; void fun() { - int count = 31; // Initialize the local count to 31 - count = 32; // Set the local count to 32 + int count = 31; // Initialize the local count to 31 + count = 32; // Set the local count to 32 } int main() { - ::count = 12; // Test 1: Set the global count to 12 + ::count = 12; // Test 1: Set the global count to 12 - A::count = 22; // Test 2: Set the count of class A to 22 + A::count = 22; // Test 2: Set the count of class A to 22 - fun(); // Test 3 + fun(); // Test 3 - return 0; + return 0; } ``` @@ -814,9 +835,11 @@ public: #### Dynamic polymorphism (runtime / late binding) * Virtual functions: decorate member functions with virtual to make them virtual +* Dynamic binding: dynamic binding occurs when a virtual function is called using a reference or pointer to a base class **note:** +* You can assign an object of a derived class to a pointer or reference of the base class, and not vice versa * Ordinary functions (non-class member functions) cannot be virtual functions * Static functions (static) cannot be virtual functions * The constructor cannot be a virtual function (because when the constructor is called, the virtual table pointer is not in the object's memory space, the virtual table pointer must be formed after the constructor is called) @@ -1022,22 +1045,6 @@ Legal, but: 3. You must ensure that the member function does not call this after `delete this` 4. Make sure no one uses it after delete this -### How to define a class that can only generate objects on the heap (on the stack)? - -> [How to define a class that can only generate objects on the heap (on the stack)?](https://www.nowcoder.com/questionTerminal/0a584aa13f804f3ea72b442a065a7618) - -#### Only on the heap - -Method: Make the destructor private - -Reason: C ++ is a static binding language. The compiler manages the life cycle of objects on the stack. When the compiler allocates stack space for class objects, it first checks the accessibility of the class's destructor. If the destructor is not accessible, the object cannot be created on the stack. - -#### Only on the stack - -Method: overload new and delete as private - -Reason: The object is generated on the heap using the new keyword operation. The process is divided into two stages: the first stage uses new to find available memory on the heap and allocates it to the object; the second stage calls the constructor to generate the object. By setting the new operation to private, the first phase cannot be completed, and objects cannot be generated on the heap. - ### Smart pointer #### In the C ++ Standard Library (STL) @@ -1093,37 +1100,62 @@ Deprecated by c ++ 11 due to lack of language features such as `std::move` seman #### static_cast -* For non-polymorphic conversions -* Do not perform runtime type checking (conversion security is not as good as dynamic_cast) -* Usually used to convert numeric data types (such as float-> int) -* You can move the pointer throughout the class hierarchy. It is safe (upward conversion) for a child class to be converted to a parent class, and it is not safe to convert a parent class to a child class (because a child class may have fields or methods that are not in the parent class) +* Compile-time type conversion (no runtime checks) +* Does not depend on RTTI -> Upcast is an implicit conversion. +| Conversion Type | Safety | Example | +|--------------------------|--------------|--------------------------| +| Numeric conversion | ✅ Safe | `float f=3.14; int i=static_cast(f);` | +| Upcast (class hierarchy) | ✅ Safe | `Derived* d; Base* b=static_cast(d);` | +| Downcast (class hierarchy)| ⚠️ Unsafe | `Base* b=new Base; Derived* d=static_cast(b);` | +| Same-type conversion | ✅ Safe | `MyClass* p; MyClass* same=static_cast(p);` | +| Explicit constructor call| ✅ Safe | `func(static_cast("text"));` | +| Any type→void* | ✅ Safe | `int* p; void* vp=static_cast(p);` | +| Enum↔Integer | ✅ Safe | `enum Color{RED}; int c=static_cast(RED);` | #### dynamic_cast -* For polymorphic type conversions -* Perform line runtime type checking -* Only applicable to pointers or references -* Conversion of ambiguous pointers will fail (return nullptr), but no exception will be thrown -* You can move the pointer throughout the class hierarchy, including up conversion, down conversion +* Runtime type checking (depends on RTTI) +* Requires polymorphic type (base must have at least one virtual function) +* Safe failure mechanism (nullptr or exception) + +| Conversion Type | Safety | Runtime Cost | Polymorphic Required | Failure Handling | Example | +|---------------------|--------|--------------|----------------------|---------------------------|---------| +| Upcast | ✅ Safe | None | ❌ Not required | Not applicable (always succeeds) | `Derived* d; Base* b = dynamic_cast(d);` | +| Downcast | ✅ Safe | Yes | ✅ Required | Pointer→`nullptr`
Reference→`std::bad_cast` | `Base* b; Derived* d = dynamic_cast(b);` | +| Cross-cast | ✅ Safe | Yes | ✅ Required | Pointer→`nullptr`
Reference→`std::bad_cast` | `B2* b2 = dynamic_cast(b1); // In diamond inheritance` | +| Same-type conversion| ✅ Safe | None | ❌ Not required | Not applicable (always succeeds) | `Derived* d2 = dynamic_cast(d1);` | +| Any type→void* | ✅ Safe | Yes | ✅ Required | `nullptr` | `void* p = dynamic_cast(obj);` | #### const_cast -* Used to remove const, volatile, and __unaligned features (such as converting const int to int) +* Compile-time type modifier operation +* Only modifies `const`/`volatile` attributes +* Does not change underlying binary representation + +| Conversion Type | Safety | Example | +|------------------------|--------------|----------------------------------| +| Remove const | ⚠️ Risky | `const int* cp; int* p=const_cast(cp);` | +| Remove volatile | ⚠️ Risky | `volatile int* vp; int* p=const_cast(vp);` | +| Add const | ✅ Safe | `int* p; const int* cp=const_cast(p);` | +| Legacy API compatibility | ⚠️ Necessary risk | `legacy_api(const_cast(str.c_str()));` | #### reinterpret_cast -* Simple reinterpretation for bits -* Misuse of the reinterpret_cast operator can be very risky. Unless the required conversion itself is low-level, you should use one of the other cast operators. -* Allows conversion of any pointer to any other pointer type (such as `char *` to `int *` or `One_class *` to `Unrelated_class *`, but it is not itself safe) -* Also allows conversion of any integer type to any pointer type and reverse conversion. -* The reinterpret_cast operator cannot lose const, volatile, or __unaligned attributes. -* A practical use of reinterpret_cast is in a hash function, which is to map values to indexes by making two different values hardly end with the same index. +* No compile-time type safety checks +* Binary bit-level reinterpretation +* Most dangerous cast operator + +| Conversion Type | Safety | Example | +|------------------------|--------------|----------------------------------| +| Pointer↔Pointer | ❌ High risk | `MyClass* obj; void* p=reinterpret_cast(obj);` | +| Pointer↔Integer | ❌ High risk | `intptr_t addr=reinterpret_cast(&obj);` | +| Function pointer conversion | ❌ Extreme risk | Converting function pointers with different signatures | +| Memory-mapped I/O | ⚠️ Systems programming | Hardware register access | #### bad_cast -* The dynamic_cast operator throws a bad_cast exception because the cast to a reference type fails. +* The exception type for a failed reference conversion using `dynamic_cast`. bad_cast demo @@ -1138,14 +1170,10 @@ catch (bad_cast b) { ### Runtime Type Information (RTTI) -#### dynamic_cast - -* For polymorphic type conversions - #### typeid * The typeid operator allows determining the type of an object at runtime -* type \ _id returns a reference to a type \ _info object +* typeid returns a reference to a type\_info object * If you want to get the data type of the derived class through the pointer of the base class, the base class must have a virtual function * Can only get the actual type of the object @@ -1210,11 +1238,11 @@ void doSomething(Flyable *obj) // do something } int main(){ - Bird *b = new Bird(); - doSomething(b); - delete b; - b = nullptr; - return 0; + Bird *b = new Bird(); + doSomething(b); + delete b; + b = nullptr; + return 0; } ``` @@ -1355,10 +1383,10 @@ Sequential stack data structures and pictures ```cpp typedef struct { - ElemType *elem; - int top; - int size; - int increment; + ElemType *elem; + int top; + int size; + int increment; } SqStack; ``` @@ -1370,10 +1398,10 @@ Queue data structure ```cpp typedef struct { - ElemType * elem; - int front; - int rear; - int maxSize; + ElemType * elem; + int front; + int rear; + int maxSize; }SqQueue; ``` @@ -1401,10 +1429,10 @@ Sequence table data structure and pictures ```cpp typedef struct { - ElemType *elem; - int length; - int size; - int increment; + ElemType *elem; + int length; + int size; + int increment; } SqList; ``` @@ -1484,14 +1512,14 @@ Hash table data structure and pictures for linear detection typedef char KeyType; typedef struct { - KeyType key; + KeyType key; }RcdType; typedef struct { - RcdType *rcd; - int size; - int count; - bool *tag; + RcdType *rcd; + int size; + int count; + bool *tag; }HashTable; ``` @@ -1836,12 +1864,12 @@ For non-threaded systems: #### Communication between processes and advantages and disadvantages * Pipeline (PIPE) - * Famous Pipeline: A half-duplex communication method that allows communication between unrelated processes + * Named pipes: A first-in-first-out communication method that allows communication between unrelated processes * Advantages: can achieve inter-process communication in any relationship * Disadvantages: 1. Long-term storage in the system, improper use is prone to errors Limited buffer - * Unnamed pipe: a half-duplex communication method that can only be used between processes with parental relationships (parent-child processes) + * Anonymous pipes: A simplex first-in-first-out communication method that can only be used between processes with affinity (parent-child processes) * Advantages: simple and convenient * Disadvantages: Limited to one-way communication @@ -2010,14 +2038,14 @@ using namespace std; int main() { - int i = 0x12345678; + int i = 0x12345678; - if (*((char*)&i) == 0x12) - cout << "Big endian" << endl; - else - cout << "Little endian" << endl; + if (*((char*)&i) == 0x12) + cout << "Big endian" << endl; + else + cout << "Little endian" << endl; - return 0; + return 0; } ``` @@ -2156,7 +2184,7 @@ application: #### Interior Gateway Protocol * RIP (Routing Information Protocol, Routing Information Protocol) -* OSPF (Open Sortest Path First) +* OSPF (Open Shortest Path First) #### External gateway protocol @@ -2203,7 +2231,7 @@ Port number | 21 | 23 | 25 | 53 | 69 | 80 | 443 | 161 Feature: * Connection oriented -* Only point-to-point (one-to-one) communication +* End-to-end communication * Reliable interaction * Full-duplex communication * Byte stream oriented @@ -2651,7 +2679,7 @@ So there is a FIN and ACK in each direction. * Basic lock types: exclusive lock (X lock / write lock), shared lock (S lock / read lock). * Livelock deadlock: * Livelock: The transaction is always in a waiting state, which can be avoided through a first come, first served policy. - * Deadlock: Things can never end + * Deadlock: The transaction can never end * Prevention: one-time block method, sequential block method; * Diagnosis: timeout method, waiting graph method; * Cancel: Undo the transaction with the least deadlock cost and release all the locks of this transaction, so that other transactions can continue to run. @@ -3387,7 +3415,7 @@ contain: ## 📝 Interview Question Experience -* [Newcoder.com's summary of the 2020 autumn tricks! (Post division)](https://www.nowcoder.com/discuss/205497) +* [Nowcoder.com's summary of the 2020 autumn tricks! (Post division)](https://www.nowcoder.com/discuss/205497) * [【Preparation for Autumn Moves】 Raiders for 2020 Autumn Moves](https://www.nowcoder.com/discuss/197116) * [2019 School Recruitment Summary! 【Daily Update】](https://www.nowcoder.com/discuss/90907) * [2019 School Recruitment Technology Posts Summary [Technology]](https://www.nowcoder.com/discuss/146655) @@ -3395,8 +3423,8 @@ contain: * [2017 Autumn Campus Recruitment Pen and Face Summaries](https://www.nowcoder.com/discuss/12805) * [The most complete collection of 2017 spring tricks in history!!](https://www.nowcoder.com/discuss/25268) * [Interview questions are here](https://www.nowcoder.com/discuss/57978) -* [Knowing.. On the Internet job search, what well-written and attentive face have you seen? It is best to share your own facial and mental journey. ](https://www.zhihu.com/question/29693016) -* [Know. What are the most common interview algorithm questions for internet companies? ](https://www.zhihu.com/question/24964987) +* [zhihu. On the Internet job search, what well-written and attentive face have you seen? It is best to share your own facial and mental journey. ](https://www.zhihu.com/question/29693016) +* [zhihu. What are the most common interview algorithm questions for internet companies? ](https://www.zhihu.com/question/24964987) * [CSDN. C ++ Interview Questions Completely Organized](http://blog.csdn.net/ljzcome/article/details/574158) * [CSDN. Baidu R & D interview questions (C ++ direction)](http://blog.csdn.net/Xiongchao99/article/details/74524807?locationNum=6&fps=1) * [CSDN. C ++ 30 common interview questions](http://blog.csdn.net/fakine/article/details/51321544) @@ -3410,7 +3438,7 @@ contain: ## 📆 Recruiting time posts -* [Niuke.com 2020 School Recruitment | 2020 IT Enterprise Recruitment Schedule](https://www.nowcoder.com/school/schedule) +* [nowcoder . Enterprise Recruitment Schedule](https://www.nowcoder.com/school/schedule) @@ -3431,4 +3459,4 @@ contain: This repository follows the CC BY-NC-SA 4.0 (signed-non-commercial use-shared in the same way) agreement, please indicate the source when reprinting, and should not be used for commercial purposes. -[![CC BY-NC-SA 4.0](https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png)](https://github.com/huihut/interview/blob/master/LICENSE) +[![CC BY-NC-SA 4.0](https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png)](https://github.com/huihut/interview/blob/master/LICENSE) \ No newline at end of file From 2128664604ac84c89238d98e41c08aa147469e52 Mon Sep 17 00:00:00 2001 From: LBX Date: Fri, 22 Aug 2025 15:41:31 +0800 Subject: [PATCH 20/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- STL/STL.md | 588 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 556 insertions(+), 32 deletions(-) diff --git a/STL/STL.md b/STL/STL.md index d1bd8c17..673071ab 100644 --- a/STL/STL.md +++ b/STL/STL.md @@ -2045,17 +2045,418 @@ mylist contains: 19 77 2 16 ``` ### list +list是一个双向链表容器,它存储元素的顺序由元素被插入的顺序决定,而不是由元素的值决定。list 不对元素进行排序,也不提供基于键的快速访问。 +#### list::front,list::back +返回第一个与最后一个元素的引用,如果容器为空,则调用该函数会导致未定义行为。 +```cpp +reference front(); +const_reference front() const; +reference back(); +const_reference back() const; +``` +Example +```cpp +#include +#include + +int main() +{ + std::list mylist = {20, 30, 40, 50}; + mylist.front() = 10; + mylist.back() = 99; + std::cout << "mylist contains:"; + for (auto& x : mylist) std::cout << ' ' << x; + std::cout << '\n'; + return 0; +} +``` +Output +```cpp +mylist contains: 10 30 40 99 +``` + +#### list::unique +移除容器中所有连续重复的元素,只保留一个。如果提供了比较函数,则使用该函数来判断元素是否相等。否则使用默认的比较函数operator==。 +```cpp +template +void unique(BinaryPredicate pred); +``` +Example +```cpp +#include +#include +int main() +{ + std::list mylist = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4}; + mylist.unique(); + std::cout << "mylist contains:"; + for (int& x : mylist) + std::cout << ' ' << x; + return 0; +} +``` +Output +```cpp +mylist contains: 1 2 3 4 +``` + +#### list::merge +将两个已排序的list合并为一个有序的list。如果this和other中的元素都按非递减顺序排序,则merge会将other中的所有元素合并到this中,合并后的this仍然保持非递减顺序,other清空元素。如果this和other指向同一个list,则行为未定义。 +```cpp +template +void merge(std::list& other, Compare comp); +``` +Example +```cpp +#include +#include +int main() +{ + std::list first = {1, 3, 5, 7}; + std::list second = {2, 4, 6, 8}; + first.merge(second); + std::cout << "first contains:"; + for (int& x : first) std::cout << ' ' << x; + std::cout << '\n'; + std::cout << "second contains:"; + for (int& x : second) std::cout << ' ' << x; + return 0; +} +``` +Output +```cpp +first contains: 1 2 3 4 5 6 7 8 +second contains: +``` + +#### list::splice +移除other中指定区间的元素,并插入到this中。 +```cpp +void splice(iterator it, list& x, iterator first); +``` +Example +```cpp +#include +#include +int main() { + std::list list1 = {1, 3, 5, 7}; + std::list list2 = {2, 4, 6, 8}; + auto it = list1.begin(); + std::advance(it, 2);//Not support + for iterator + auto first = list2.begin(); + std::advance(first, 1); + list1.splice(it, list2, first); + for (int value : list1) { + std::cout << value << " "; + } + std::cout << std::endl; + for (int value : list2) { + std::cout << value << " "; + } + std::cout << std::endl; + return 0; +} +``` +Output: +```cpp +1 3 4 5 7 +2 6 8 +``` + +#### list::reverse +反转容器中的元素。 +```cpp +void reverse() noexcept; +``` +Example: +```cpp +#include +#include +int main() +{ + std::list mylist = {1, 2, 3, 4, 5}; + mylist.reverse(); + std::cout << "mylist contains:"; + for (int& x : mylist) std::cout << ' ' << x; + return 0; +} +``` +Output: +```cpp +mylist contains:1 2 3 4 5 +``` ### stack +后进先出(LIFO),基于底层容器(deque或list或vector)实现。 +#### stack::emplace +在栈顶构造一个新元素,减少了不必要的对象构造和销毁. +```cpp +template +void emplace(Args&&... args); +``` +Example: +```cpp +#include +#include +int main() +{ + std::stack mystack; + mystack.emplace(10); + mystack.emplace(20); + std::cout << "mystack contains:"; + while (!mystack.empty()) + { + std::cout << ' ' << mystack.top(); + mystack.pop(); + } + return 0; +} +``` +Output: +```cpp +mystack contains: 20 10 +``` + +#### stack::push_range(c++23) +将范围中的每个元素插入到栈的末尾 +```cpp +template +void push_range(InputIterator first, InputIterator last); +``` +Example: +```cpp +#include +#include +#include +int main() { + std::stack st; + std::vector vec = {1, 2, 3, 4}; + st.push_range(vec); + while (!st.empty()) { + std::cout << st.top() <<" "; + st.pop(); + } +} +``` +Output: +```cpp +4 3 2 1 +``` ### queue +先进先出(FIFO),基于底层容器(deque或list)实现。 + ### priority_queue -### set +提供了一种基于优先级的队列,通常基于堆实现,默认使用最大堆。 +#### lambda自定义函数比较 +```cpp +#include +#include +#include +int main() { + std::priority_queue maxHeap; + maxHeap.push(10); + maxHeap.push(20); + maxHeap.push(15); + std::cout << "Top element (max): " << maxHeap.top() << std::endl; + maxHeap.pop(); + std::cout << "Top element after pop: " << maxHeap.top()< b; };//lambda + std::priority_queue, decltype(cmp)> minHeap(cmp); + minHeap.push(10); + minHeap.push(20); + minHeap.push(15); + std::cout << "Top element (min): " << minHeap.top() << std::endl; + return 0; +} +``` +Output: +```cpp +Top element (max): 20 +Top element after pop: 15 +Top element (min): 10 +``` +### set +存储唯一的元素,并且这些元素会自动按照特定的顺序排列. +#### set::upper_bound +返回指向第一个大于指定值的元素的迭代器。 +```cpp +template +iterator upper_bound(const K& x); +template +const_iterator upper_bound(const K& x) const; +``` +Example: +```cpp +#include +#include +#include +int main() { + std::set mySet = {"apple", "banana", "cherry", "date"}; + auto it = mySet.upper_bound("banana"); + if (it != mySet.end()) { + std::cout << "The first element greater than 'banana' is: " << *it; + } else { + std::cout << "No element greater than 'banana' found."; + } + return 0; +} +``` +Output: +```cpp +The first element greater than 'banana' is: cherry +``` +#### set::contains +判断元素是否存在。 +```cpp +bool contains(const key_type& key) const; +``` +Example: +```cpp +#include +#include +int main() { + std::set mySet = {1, 2, 3, 4, 5}; + int valueToFind = 3; + if (mySet.contains(valueToFind)) { + std::cout << valueToFind << " is in the set."; + } else { + std::cout << valueToFind << " is not in the set."; + } + return 0; +} +``` +Output: +```cpp +3 is in the set. +``` +#### set::value_comp +获取一个函数对象,用于比较两个键值。 +```cpp +key_compare value_comp() const; +``` +Example: +```cpp +#include +#include +int main() { + std::set mySet = {5, 3, 9, 1, 7}; + auto comp = mySet.value_comp(); + int a = 3; + int b = 5; + if (comp(a, b)) { + std::cout << a << " is less than " << b << " according to the set's comparison function."; + } else { + std::cout << a << " is not less than " << b << " according to the set's comparison function."; + } + return 0; +} +``` +Output: +```cpp +3 is less than 5 according to the set's comparison function. +``` +#### set::extract +从set中提取指定的元素节点,并返回一个节点句柄。 +```cpp +template +node_type extract(K&& x); +``` +Example: +```cpp +#include +#include +int main() { + std::set mySet = {1, 2, 3, 4, 5}; + auto nh = mySet.extract(3); + if (!nh.empty()) { + std::cout << "Extracted element: " << nh.value(); + } else { + std::cout << "Element not found."; + } + std::cout< +#include +int main() { + std::multiset ms = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4}; + auto range = ms.equal_range(3); + for (auto it = range.first; it != range.second; ++it) { + std::cout << *it << " "; + } + return 0; +} +``` +Output: +```cpp +3 3 3 +``` +#### multset::find +返回一个迭代器,指向给定键的元素。如果找不到给定键,则返回一个指向 multiset 的末尾的迭代器。 +Example: +```cpp +#include +#include +int main() { + std::multiset myMultiset = {1, 2, 2, 3, 4, 4, 4}; + auto it = myMultiset.find(2); + if (it != myMultiset.end()) { + std::cout << "Found element with value " << *it << std::endl; + } else { + std::cout << "Element not found" << std::endl; + } + return 0; +} +``` +Output: +```cpp +Found element with value 2 +``` +#### multiset::emplace_hint +通过提供一个位置,帮助优化插入操作的性能。 +```cpp +template +iterator emplace_hint(const_iterator hint, Args&&... args); +``` +Example: +```cpp +#include +#include +int main() { + std::multiset myMultiset{1, 2, 4, 5}; + auto it = myMultiset.find(2); + myMultiset.emplace_hint(it, 3);//Given position of 2 + for (const auto& elem : myMultiset) { + std::cout << elem << " "; + } + return 0; +} +``` +Output: +```cpp +1 2 3 4 5 +``` ### map map 是关联容器,按照特定顺序存储由 key value (键值) 和 mapped value (映射值) 组合形成的元素。 @@ -2505,35 +2906,7 @@ upper bound points to: 'c' => 30 ``` ### multimap - -### 无序容器(Unordered Container):unordered\_set、unordered\_multiset、unordered\_map、unordered\_multimap - -包括: - -* unordered\_set -* unordered\_multiset -* unordered\_map -* unordered\_multimap - -都是以哈希表实现的。 - -![](http://img.blog.csdn.net/20160410123436394) - -unordered\_set、unodered\_multiset结构: - -![](http://img.blog.csdn.net/20160410123518692) - -unordered\_map、unodered\_multimap结构: - -![](http://img.blog.csdn.net/20160410123525739) - -### unordered_set - -### unordered_multiset - -### unordered_map - -### unordered_multimap +在map的基础上,允许重复元素。 ### tuple @@ -2672,7 +3045,82 @@ Output ``` sixth contains: 30 and c ``` - +#### tuple::tie +将元组中的值解包到多个变量中. +```cpp +template +constexpr tuple tie(Types&... args); +``` +Example: +```cpp +#include +#include +int main() { + std::tuple myTuple(42, 3.14, "Hello"); + int a; + double b; + std::string c; + std::tie(a, b, c) = myTuple; + std::cout << "a: " << a << "\n"; + std::cout << "b: " << b << "\n"; + std::cout << "c: " << c << "\n"; + return 0; +} +``` +Output: +```cpp +a: 42 +b: 3.14 +c: Hello +``` +#### tuple::apply(c++23) +将函数 F 应用于 tuple t +```cpp +template +constexpr decltype(auto) apply(F&& f, Tuple&& t); +``` +Example: +```cpp +#include +#include +void print(int a, double b, const std::string& c) { + std::cout << "a: " << a << ", b: " << b << ", c: " << c << "\n"; +} +int main() { + std::tuple myTuple(42, 3.14, "Hello"); + std::apply(print, myTuple); + return 0; +} +``` +Output: +```cpp +a: 42, b: 3.14, c: Hello +``` +#### tuple::ignore +解包操作中忽略某个值。 +```cpp +namespace std { + struct _Ignored {}; + _Ignored const ignore; +} +``` +Example: +```cpp +#include +#include +int main() { + std::tuple t(1, 2.5, "hello", 'a'); + int a; + std::string c; + std::tie(a, std::ignore, c, std::ignore) = t; + std::cout << "a: " << a << ", c: " << c << std::endl; + return 0; +} +``` +Output: +```cpp +a: 1, c: hello +``` ### pair 这个类把一对值(values)结合在一起,这些值可能是不同的类型(T1 和 T2)。每个值可以被公有的成员变量first、second访问。 @@ -2756,3 +3204,79 @@ The price of lightbulbs is $0.99 The price of shoes is $39.9 The price of tomatoes is $2.3 ``` +### span +提供了一种方便的方式来引用连续的内存块。span不复制数据,使用方式类似于指针或引用,提供了更高的性能。 + +#### span::first +获取一个包含span前count个元素的子视图。 +```cpp +template +constexpr std::span first() const; +``` +Example: +```cpp +#include +#include +#include +int main() { + std::vector vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + std::span span(vec); + auto first3 = span.first<3>(); + std::cout << "First 3 elements: "; + for (int i : first3) { + std::cout << i << " "; + } + return 0; +} +``` +Output: +```cpp +First 3 elements: 1 2 3 +``` +#### span::subspan +获取一个包含span中从offset开始的count个元素的子视图。 +```cpp +constexpr std::span subspan(std::size_t offset, std::size_t count) const; +``` +Example: +```cpp +#include +#include +#include +int main() { + std::vector vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + std::span span(vec); + auto subspan1 = span.subspan(2, 3); + std::cout << "Subspan : "; + for (int i : subspan1) { + std::cout << i << " "; + } + return 0; +} +``` +Output: +```cpp +Subspan : 3 4 5 +``` +### 无序容器(基于哈希表实现) +![](http://img.blog.csdn.net/20160410123436394) + +#### unordered_set +存储唯一的元素,不允许重复,元素的顺序是无序的。 +#### unordered_multiset +存储元素,允许重复,元素的顺序是无序的。 +#### unordered_map +存储键值对,键是唯一的,元素的顺序是无序的。 +#### unordered_multimap +存储键值对,允许键重复,元素的顺序是无序的。 +### 平坦容器(C++23) +使用连续的存储空间,速度优化。 +![](http://img.blog.csdn.net/20160410123436394) + +#### flat_set + +#### flat_multiset + +#### flat_map + +#### flat_multimap \ No newline at end of file