C++风格指南 2、作用域

news2024/9/25 1:18:46

2.1. 命名空间

这段文字的关键内容概括如下:

1. 命名空间的使用:除了少数特殊情况外,代码应在命名空间内,命名空间名称应唯一,包含项目名和可选的文件路径。

2. 禁止使用:
   - `using` 指令引入整个命名空间。
   - 内联命名空间。

3. 命名空间定义:命名空间用于划分全局作用域,防止命名冲突。

4. 优点:避免大型程序中的命名冲突,允许使用简短名称。

举例来说, 若两个项目的全局作用域中都有一个叫 Foo 的类 (class), 这两个符号 (symbol) 会在编译或运行时发生冲突. 如果每个项目在不同的命名空间中放置代码, project1::Foo 和 project2::Foo 就是截然不同的符号, 不会冲突.

内联命名空间会自动把其中的标识符置入外层作用域, 比如:

namespace outer {
inline namespace inner {
    void foo();
}  // namespace inner
}  // namespace outer

此时表达式 outer::inner::foo() 与 outer::foo() 等效.

5. 缺点:
   - 难以理解,难以找到标识符的定义。
   - 内联命名空间更难理解,标识符出现在多个作用域。

6. 使用建议:
   - 遵守命名空间命名规则。
   - 在文件末尾注释命名空间名称。
   - 在导入语句后,用命名空间包裹整个源代码文件。

7. 复杂文件处理:更复杂的 `.cc` 文件可能包含旗标、`using` 声明等,在命名空间内处理。

8. Proto 消息命名空间:使用 `package` 修饰符将自动生成的 proto 消息代码放入命名空间。

9. std 命名空间:不在 `std` 命名空间内声明任何东西不前向声明标准库类

10. using 指令:禁止使用 using 指令 引入命名空间的所有符号。

/ 禁止: 这会污染命名空间.
using namespace foo;

11. 命名空间别名:可以在内部使用的命名空间内使用别名,不在头文件引入别名作为公开 API。

12. 内部命名空间:如果命名空间名称包含 "internal",则不应由用户使用这些 API。

13. 单行嵌套命名空间声明:鼓励使用,但不强制。

例如

namespace foo::bar {
...
}  // namespace foo::bar

2.2. 内部链接

1. 使用场景:如果 `.cc` 文件中的定义不需要被其他文件使用(即仅该.cc文件使用),应使用匿名命名空间`static` 关键字以实现内部链接。但是不要在 .h 文件中使用这些手段。

2. 定义:
   - 匿名命名空间:所有在其中声明的内容都具有内部链接,其他文件无法访问。
   - `static` 函数和变量:也具有内部链接,即使名称相同,在不同文件中也是独立的。

3. 结论:
   - 推荐 `.cc` 文件中不需要外部使用的代码采用内部链接。
   - 不应在 `.h` 文件中使用内部链接。

4. 匿名命名空间声明:声明方式与具名命名空间相同,但在注释中不需要注明命名空间名称。

 //匿名命名空间

namespace { ... } // namespace

 

2.3. 非成员函数、静态成员函数和全局函数 

1. 命名空间推荐:建议将非成员函数放入命名空间避免使用完全全局的函数

2. 使用类的限制:不要仅为了给静态成员分组而使用类,类的静态方法应与类的实例或静态数据紧密相关。                                                

3. 优点:
   - 将非成员函数放在命名空间内,可以避免污染全局命名空间。

4. 缺点:
   - 非成员函数和静态成员函数有时更适合作为新类的成员,特别是当它们需要访问外部资源或存在明显依赖关系时。

5. 结论:
   - 定义与类实例无关的函数时,可以选择静态成员函数或非成员函数。
   - 非成员函数不应依赖外部变量,大多数情况下应位于命名空间中
   - 不要为了静态成员分组而创建新类,避免不必要的公共前缀。
   - 如果非成员函数仅供 `.cc` 文件使用,应使用内部链接限制其作用域。
 

2.4. 局部变量

这段文字的关键内容概括如下:

1. 缩小作用域:应尽可能缩小函数变量的作用域,并在声明的同时初始化

2. 变量声明位置:提倡在函数中靠近第一次使用的位置声明变量,便于读者理解变量类型和初始值。

3. 初始化方式:
   - 推荐直接初始化变量,如 `int i = f();`。
   - 不推荐先声明后赋值,如 `int i; i = f();`。

4. 立即使用:变量初始化后应尽快使用,避免初始化和使用位置分离。

5. 容器初始化:推荐使用初始化列表立即初始化容器,如 `vector<int> v = {1, 2};`。

6. 语句内声明:建议在 `if`、`while` 和 `for` 语句内声明变量,限制其作用域。

7. 对象构造和析构:注意对象每次进入作用域会构造,退出作用域会析构,避免在循环内频繁构造和析构对象。效率问题:避免在循环体内声明对象,以减少构造和析构函数的调用次数,提高效率。循环外声明:对于循环中使用的变量,应在循环外声明,以调用构造函数和析构函数各一次。

2.5. 静态和全局变量

1. 禁止使用静态储存周期变量:除非它们的析构函数平凡(即默认析构函数),即不会执行任何操作,包括成员和基类的析构函数。

2. 平凡析构要求:变量类型没有用户定义的析构函数或虚析构函数,且所有成员和基类也能平凡地析构。

3. 局部静态变量:函数的局部静态变量可以动态初始化,但不推荐静态类成员变量或命名空间内的变量进行动态初始化

4. 经验规则:如果全局变量的声明可以作为常量表达式(`constexpr`),则满足要求。

5. 静态储存周期定义:对象的存活时间从程序初始化开始到结束,包括全局变量、类的静态数据成员、用 `static` 修饰的函数局部变量。

6. 初始化过程:静态储存周期对象的初始化可能是动态的(包含非平凡操作),也可能是静态的(初始化为常量或清零)。

7. 优点:全局或静态变量有助于实现具名常量、辅助数据结构、命令行旗标、日志、注册机制等。

8. 缺点:
   - 动态初始化和非平凡析构函数全局和静态变量增加代码复杂度和错误风险。
   - 不同编译单元的动态初始化顺序不确定,析构顺序一定是初始化顺序的逆序。
   - 静态变量的初始化可能引用其他生命周期外的静态变量。
   - 未汇合的线程可能在静态变量析构后继续访问这些变量。

9. 风险提示:使用全局和静态变量时要注意初始化顺序和线程安全问题。
 

1. 析构函数的限制:只有具有平凡析构函数的对象才能使用静态储存周期。平凡析构函数不执行任何操作,包括成员和基类的析构函数。

2. 允许的静态储存周期变量:
   - 基本类型(如指针和 `int`)可以平凡地析构。
   - 用 `constexpr` 修饰的变量可以平凡地析构。

   - 可平凡析构的类型所构成的数组也可以平凡地析构
   - 例如 `const int`、`const` 结构体数组、`constexpr` 数组。

3. 不允许的静态储存周期变量:
   - 具有非平凡析构函数的对象,如 `std::string`、`std::map`。

4. 引用的规则:引用不是对象,其生命周期不受限,但需遵守动态初始化的限制。

5. 初始化的复杂性:初始化不仅涉及构造函数的执行,还涉及初始化表达式的求值。

6. 常量初始化:使用常量表达式进行初始化,构造函数也必须声明为 `constexpr`。

7. 允许的初始化:
   - 直接使用字面值初始化基本类型。
   - 使用 `constexpr` 构造函数初始化对象。(constexpr允许编译器在编译阶段就计算出某些值,而不是在运行时计算。)

C++中const和constexpr的区别:了解常量的不同用法_c++ const和const expr的区别-CSDN博客

8. 有问题的初始化:
   - 使用非 `constexpr` 函数的结果进行初始化。
   - 使用非 `constexpr` 构造函数的对象。

9. 禁止全局变量的动态初始化:但如果初始化过程不依赖于其他变量的初始化顺序,则可以允许。

10. 静态局部变量的动态初始化:通常是允许的。

11. 使用 `constexpr` 或 `constinit` 标记:对静态变量使用这些标记以表明使用了常量初始化。

12. 谨慎检查:对于没有 `constexpr` 或 `constinit` 标记的静态变量,应假设它们是动态初始化的,并进行谨慎检查。


常用的语法结构

1. 全局字符串:推荐使用 `constexpr` 修饰的 `string_view` 变量、字符数组或指向字符串字面量的字符指针,因为字符串字面量具有静态储存周期

2. 动态容器:避免使用标准库的动态容器(如 `std::map`、`std::vector` 等)作为静态变量,因为它们具有非平凡析构函数。推荐使用平凡类型的数组或数对数组作为替代。

3. 智能指针:由于智能指针在析构时会释放资源,因此不能作为静态变量。考虑使用裸指针指向动态分配的对象,并且永不删除。

4. 自定义类型的静态变量:如果静态数据是自定义类型,请确保该类型具有平凡析构函数和 `constexpr` 构造函数。

5. 函数内局部静态指针:如果上述方法都不适用,可以使用函数内局部静态指针或引用,动态分配对象并永不删除,例如 `static const auto& impl = *new T(args...);`。
 

2.6. thread_local 变量

1. thread_local 变量初始化:必须使用编译时常量初始化函数外定义的 `thread_local` 变量,并使用 `ABSL_CONST_INIT` 属性强制执行。

2. 定义:`thread_local` 修饰的变量在每个线程中都有不同的对象实例,类似于静态储存周期的变量,但每个线程启动时初始化。

3. 优点:
   - `thread_local` 可以防止竞态条件,有助于并行化。
   - 是语法标准支持的唯一创建线程局部数据的方法。

4. 缺点:
   - 线程启动或首次使用 `thread_local` 变量可能触发不可预测的代码
   - thread_local 本质上是全局变量. 除了线程安全以外, 它具有全局变量的所有其他缺点.具有全局变量的缺点,除了线程安全外。
   - 内存占用可能随线程数量增加而变得巨大。
   - 析构顺序可能导致野指针问题,特别是如果 `thread_local` 变量的析构函数访问了其他可能已被销毁的 `thread_local` 变量。

5. 决定:
   - 类或命名空间中的 `thread_local` 变量必须用真正的编译时常量初始化,使用 `ABSL_CONST_INIT` 修饰
   - 函数中的 `thread_local` 变量没有初始化问题,但存在析构时使用已销毁对象的风险。

6. 模拟类或命名空间中的 `thread_local`:
   - 可以使用静态方法暴露函数内的 `thread_local` 变量。

7. 建议:
   - 优先使用 `thread_local` 定义线程的局部数据,而非其他机制。
   - 使用简单的类型或析构函数中没有自定义代码的类型,以减少访问其他 `thread_local` 变量的可能性。

8. 注意事项:
   - 避免在 `thread_local` 变量的析构函数中访问可能已被销毁的其他 `thread_local` 变量。
   - 预防全局/静态变量的野指针方法不适用于 `thread_local`,因为跳过析构函数可能导致资源泄漏与线程数量成正比。

2.7 后记

  1. 局部变量在声明的同时进行显式值初始化,比起隐式初始化再赋值的两步过程要高效,同时也贯彻了计算机体系结构重要的概念「局部性(locality)」。

  2. 注意别在循环犯大量构造和析构的低级错误。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2067804.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

实验17:直流电机实验

硬件接线图; 我这里实现的是&#xff1a;转5s&#xff0c;停5s&#xff0c;循环 main.c #include<reg52.h>typedef unsigned int u16; typedef unsigned char u8;sbit ZLP1^0;void delay_10us(u16 n) {while(n--); }void delay_ms(u16 ms) {u16 i,j;for(ims;i>0;i--…

Python中8个让你成为调试高手的技巧

文末赠免费精品编程资料~~ 调试技能是每一位开发者不可或缺的利器。它不仅能帮你迅速定位并解决代码中的bug&#xff0c;还能提升你的编程效率&#xff0c;让你的代码更加健壮。今天&#xff0c;我们就来揭秘10个让你从新手进阶为调试高手的秘诀。 1. 使用print()函数——基础…

AIoTedge边缘物联网平台发布,更低的价格,更强大的功能

AIoTedge是一个创新的AI边缘计算平台&#xff0c;专为满足现代物联网&#xff08;IoT&#xff09;需求而设计。它采用了边云协同的架构&#xff0c;能够实现多点部署&#xff0c;并与IoT云平台无缝配合&#xff0c;提供分布式的AIoT处理能力。这种设计特别适合需要AI云端训练和…

高效率伪原创检测,6款工具为你轻松搞定

在内容创作领域&#xff0c;原创性是衡量作品价值的重要标准之一。然而&#xff0c;创作高质量的原创内容不仅需要灵感和创意&#xff0c;还需要大量的时间和精力。为了提高效率&#xff0c;许多创作者和编辑开始寻求伪原创检测工具的帮助&#xff0c;以确保他们的作品在保持独…

pat1097链表去重 | pat1133链表元素分类 【完结】

pat1097链表去重 与之前不同的是&#xff0c;需要把删掉的元素也拍成一个链表 分类讨论你就好好的分 如果重复了——pre不动&#xff0c;pre的next指向cur的next&#xff0c;然后在已删除中加上一个节点&#xff0c;状态移至下个节点&#xff08;最后完了记得加上-1&#xf…

C语言05--指针初识

内存地址 字节&#xff1a;字节是内存的容量单位&#xff0c;英文称为 byte&#xff0c;一个字节有8位&#xff0c;即 1byte 8bits地址&#xff1a;系统为了便于区分每一个字节而对它们逐一进行的编号&#xff0c;称为内存地址&#xff0c;简称地址。注:地址是按字节编号的&a…

多模态YOLOv8 融合可见光+红外光(RGB+IR)双输入【附代码】

文章目录 前言视频效果代码获取文章概述必要环境一、模型训练1、 定义数据1.1、数据集结构1.2、定义data.yaml 2、 运行方法运行效果 二、模型验证运行方法运行效果 三、模型推理1. 参数定义2. 运行方法运行效果 四、效果展示白天夜间 总结 前言 最近看不少朋友提到双模态YOLO…

基于SpringBoot的健康饮食管理系统---附源码98382

目 录 1 绪论 1.1 研究背景与意义 1.2国内外研究现状 1.3论文结构与章节安排 2 系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系统用例分析 2.4 系统流程…

什么是营销自动化?营销自动化的优势?

在SaaS行业和软件行业中&#xff0c;营销自动化作为一种先进的营销手段&#xff0c;正逐渐受到企业的青睐。营销自动化基于大数据和人工智能技术&#xff0c;能够自动执行、管理和完成营销任务和流程&#xff0c;为企业带来诸多优势。 营销自动化是一种能够一体化执行、管理、…

SecretPixel:一款整合了多种技术的高级图像隐写工具

关于SecretPixel SecretPixel是一款先进的隐写术工具&#xff0c;旨在安全地隐藏图像中的敏感信息。它结合了先进的加密、压缩和种子最低有效位 (LSB) 技术&#xff0c;为隐藏数据提供了一种不可检测的强大解决方案&#xff0c;在数字隐写术领域脱颖而出。 功能介绍 1、高级加…

2024 Python3.10 系统入门+进阶(七):字符串及其常用操作详解上篇

目录 一、初始化二、索引三、常用操作3.1 拼接字符串3.1.1 ""号3.1.2 join()方法 3.2 检索字符串3.2.1 find() 方法——字符串首次出现的索引位置(rfind()、index()、rindex())3.2.2 count() 方法——统计字符串出现次数3.2.3 len() 函数——计算字符串长度或元素个数…

RabbitMQ的高可用

1.Rabbit集群 采用集群模式保护消息的完整。 1.1普通集群 在普通集群模式下&#xff0c;各个节点之间有相同的元数据&#xff0c;即队列结构&#xff0c;而消息不会冗余&#xff08;不同节点的消息不同&#xff09;。 消费时&#xff0c;如果消费的不是存有数据的节点&…

如何用Python进行民宿数据分析:一步步教你实现可视化

&#x1f34a;作者&#xff1a;计算机毕设匠心工作室 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目…

基于swifter多内核的加速Pandas DataFrame操作运行

swifter是提高pandas性能的第三方包,主要是apply函数。 接口支持范围: 运行环境和安装 操作系统是Win10 64,pandas版本是2.2.2,swifter版本是1.4.0。 pip安装 $ pip install -U pandas # upgrade pandas $ pip install swifter # first time installation $ pip inst…

Android 架构模式之 MVVM

Android 架构 Android 架构模式之 MVCAndroid 架构模式之 MVPAndroid 架构模式之 MVVM 目录 Android 架构架构设计的目的对 MVVM 的理解代码ModelViewViewModel Android 中 MVVM 的问题试吃个小李子BeanModelViewViewModel效果展示 大家好&#xff01; 作为 Android 程序猿&a…

大数据ETL工具(Sqoop, DataX, Kettle)对比

文章目录 1. ETL简介2. Sqoop2.1 Sqoop简介2.2 Sqoop主要特点 3. DataX3.1 DataX简介3.2 DataX框架设计3.3 DataX的主要特点 4. Kettle4.1 Kettle简介4.2 Kettle的主要特点 5. 工具对比5.1 DataX 与 Sqoop对比5.2 DataX 与 Kettle 6. 总结 1. ETL简介 ETL&#xff08;Extract-…

Mamba来搞图像增强了!高创新,发小论文不愁!

用Mamba做图像增强是个创新性比较高的方向&#xff0c;因为Mamba拥有非常独特的架构设计&#xff0c;能够同时捕获全局和局部的信息&#xff0c;轻松助力模型理解图像的整体结构和上下文&#xff0c;帮助我们确保图像细节的准确恢复和增强。 这种优势让它在保持高效计算的同时…

MySQL主从复制重新初始化单表或者单库的方法

作者介绍&#xff1a;老苏&#xff0c;10余年DBA工作运维经验&#xff0c;擅长Oracle、MySQL、PG、Mongodb数据库运维&#xff08;如安装迁移&#xff0c;性能优化、故障应急处理等&#xff09; 公众号&#xff1a;老苏畅谈运维 欢迎关注本人公众号&#xff0c;更多精彩与您分享…

【C++ Primer Plus习题】3.7

问题: 解答: #include <iostream> using namespace std;const float GALLO_TO_LITRE 3.785; const float KM_TO_MILE 62.14;int main() {float litre 0;float gallo 0;float mile 0;cout << "请输入汽车油耗(每100km消耗的汽油量单位为升):";cin &…

C#下在派生类中引发基类事件的方法与示例

文章目录 基类事件在派生类中的定义及触发方式基类事件的传播机制示例总结 在面向对象编程中&#xff0c;继承是代码复用的一种重要方式。C#作为一种面向对象的编程语言&#xff0c;允许派生类继承基类的属性和方法。基类定义了一系列共有的属性和行为&#xff0c;而派生类则可…