01  

C++语言编程规范-常量

02  

初始化和类型转换

声明、定义与初始化

03  

禁止用 memcpy、memset 初始化非 POD 对象

说明:POD 全称是“Plain Old Data”,是 C++ 98 标准(ISO/IEC 14882, first edition, 1998-09-01)中引入的一个概念, POD 类型主要包括 int, char, float,double,enumeration,void指针等原始类型及其集合类型,不能使用封装和面对对象特性(如用户定义的构造/赋值/析构函数、基类、虚函 数等)。

由于非 POD 类型比如非集合类型的 class 对象,可能存在虚函数,内存布局不确定,跟编译器有关,滥用内存拷贝可能会导致严重的问题。 即使对集合类型的 class,使用直接的内存拷贝和比较,破坏了信息隐蔽和数据保护的作用,也不提倡 memcpy、memset 操作。

示例:×××产品程序异常退出(core dump)。 经过现场环境的模似,程序产生 COREDUMP,其原因是:

在初始化函数内使用

     memset(this,0,sizeof(*this))

    进行了类的初始化,将类的虚函数表指针被清空,从而导致使用空指针。

    解决方案:使用 C++构造函数初始化,不要使用 memset 函数初始化类对象。

    04  

    变量使用时才声明并初始化

    说明:变量在使用前未赋初值,是常见的低级编程错误。使用前才声明变量并同时初始化,非常方便 地避免了此类低级错误。在函数开始位置声明所有变量,后面才使用变量,作用域覆盖整个函数实现,容易导致如下问题:

    ⚫ 程序难以理解和维护:变量的定义与使用分离。

    ⚫ 变量难以合理初始化:在函数开始时,经常没有足够的信息进行变量初始化,往往用某个默认的空值(比如零)来初始化,这通常是一种浪费,如果变量在被赋于有效值以前使用,还会导致错误。遵循变量作用域最小化原则与就近声明原则,使得代码更容易阅读,方便了解变量的类型和初始值。特别是,应使用初始化的方式替代声明再赋值。

    示例:

      //不好的例子:声明与初始化分离string name; //声明时未初始化:调用缺省构造函数//……. name=”zhangsan”; //再次调用赋值操作符函数;声明与定义在不同的地方,理解相对困难//好的例子:声明与初始化一体,理解相对容易string name(”zhangsan”); //调用一次构造函数

      05  

      避免构造函数做复杂的初始化,可以使用“init”函数

      说明:正如函数的变量都在函数内部初始化一样,类数据成员最好的初始化场所就是构造函数,数据成员都应该尽量在构造函数中初始化。

      以下情况可以使用 init()函数来初始化:

      ⚫ 需要提供初始化返回信息。

      ⚫ 数据成员初始化可能抛异常。

      ⚫ 数据成员初始化失败会造成该类对象初始化失败,引起不确定状态。

      ⚫ 数据成员初始化依赖 this 指针:构造函数没结束,对象就没有构造出来,构造函数内不能使用 this 成员;

      ⚫ 数据成员初始化需要调用虚函数。在构造函数和析构函数中调用虚函数,会导致未定义的行为。

      示例:数据成员初始化可能抛异常:

        class CPPRule {public:   CPPRule():size_(0), res (null) {}; //仅进行值初始化  long init(int size)   {     //根据传入的参数初始化size_, 分配资源res   } private:   int size_;   ResourcePtr* res; }; //使用方法:CPPRule a; a.init(100);

        06  

        初始化列表要严格按照成员声明顺序来初始化它们

        说明:编译器会按照数据成员在类定义中声明的顺序进行初始化,而不是按照初始化列表中的顺序,

        如果打乱初始化列表的顺序实际上不起作用,但会造成阅读和理解上的混淆;特别是成员变量之间存在依赖关系时可能导致 BUG。

        示例:

          //不好的例子:初始化顺序与声明顺序不一致class Employee public: Employee(const char* firstName, const char* lastName) : firstName_(firstName), lastName_(lastName) , email_(firstName_ + "." + lastName_ + "@huawei.com") {}; private: string email_, firstName_, lastName_; };

          类定义 email_是在 firstName_,lastName_之前声明,它将首先初始化,但使用了未初始化的 firstName_和lastName_,导致错误。在成员声明时,应按照成员相互依赖关系按顺序声明。

          07  

          类型转换

          避免使用类型分支来定制行为:类型分支来定制行为容易出错,是企图用 C++编写 C 代码的明显标志。

          这是一种很不灵活的技术,要添加新类型时,如果忘记修改所有分支,编译器也不会告知。使用模板和虚函数,让类型自己而不是调用它们的代码来决定行为。

          08  

          使用 C++风格的类型转换,不要使用 C 风格的类型转换

          说明:C++的类型转换由于采用关键字,更醒目,更容易查找,编程中强迫程序员多停留思考片刻,谨慎使用强制转换。

          C++使用 const_cast, dynamic_cast, static_cast, reinterpret_cast 等新的类型转换,它们允许用户选择适当级别的转换符,而不是像 C 那样全用一个转换符。

          dynamic_cast:主要用于下行转换,dynamic_cast 具有类型检查的功能。dynamic_cast 有一定的开销,建议在调测代码中使用。

            #include <iostream>#include<typeinfo>class Base {public:    virtual ~Base() {} // 需要虚函数才能启用RTTI};class Derived : public Base {public:    void derived_func() {        std::cout << "Derived function called" << std::endl;    }};int main() {    Base* base_ptr = new Derived();    // 使用 dynamic_cast 进行安全的下行转换    Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);    if (derived_ptr) {        std::cout << "转换成功" << std::endl;        derived_ptr->derived_func(); // 安全调用派生类函数    } else {        std::cout << "转换失败" << std::endl;    }    // 尝试转换不匹配的类型    Derived* another_ptr = dynamic_cast<Derived*>(new Base());    if (another_ptr) {        std::cout << "转换成功" << std::endl;    } else {        std::cout << "转换失败" << std::endl;    }    delete base_ptr;    delete another_ptr;    return 0;}

            对于引用类型的 dynamic_cast:

              #include<iostream>#include <typeinfo>class Base {public:    virtual ~Base() {}};class Derived : public Base {public:    void derived_func() {        std::cout << "Derived function called" << std::endl;    }};void process(Base& base) {    try {        Derived& derived = dynamic_cast<Derived&>(base);        std::cout << "转换成功" << std::endl;        derived.derived_func();    } catch (const std::bad_cast& e) {        std::cout << "转换失败: " << e.what() << std::endl;    }}int main() {    Derived derived;    Base base;    std::cout << "处理 Derived 对象:" << std::endl;    process(derived); // 转换成功    std::cout << "\n处理 Base 对象:" << std::endl;    process(base);    // 转换失败    return 0;}

              static_cast:和 C 风格转换相似可做值的强制转换,或上行转换(把派生类的指针或引用转换成基类的指针或引用)。该转换经常用于消除多重继承带来的类型歧义,是相对安全的。下行转换(把基类的

              指针或引用转换成派生类的指针或引用)时,由于没有动态类型检查,所以不安全的,不提倡下行转换。

              上行转换(派生类到基类)- 这是 static_cast 最安全的用法之一

                class Base {public:    virtual ~Base() {}    virtual void base_func() { std::cout << "Base function" << std::endl; }};class Derived : public Base {public:    void derived_func() { std::cout << "Derived function" << std::endl; }};int main() {    Derived derived;    Base* base_ptr = static_cast<Base*>(&derived); // 上行转换,安全    base_ptr->base_func(); // 调用基类函数    return 0;}

                reinterpret_cast:用于转换不相关的类型。reinterpret_cast 强制编译器将某个类型对象的内存新解释成另一种类型,相关代码可移植不好。建议对 reinterpret_cast<>的用法进行注释,有助于减少维

                护者在看到这种转换时的顾虑。

                良好的编码实践:添加注释

                  // 注意:这里使用 reinterpret_cast 是因为我们需要将特定内存区域// 解释为另一种类型,这是平台相关的操作,不具有可移植性class MemoryMappedDevice {public:    MemoryMappedDevice(void* base_addr)         : control(reinterpret_cast<volatile uint32_t*>(base_addr)),          data(reinterpret_cast<volatile uint32_t*>(static_cast<uintptr_t>(base_addr) + 4)) {}private:    volatile uint32_t* control;    volatile uint32_t* data;};

                  const_cast:用于移除对象的 const 属性,使对象变得可修改。

                    int main() {    const int ci = 10;    const int* ci_ptr = &ci;    // 移除 const 属性    int* i_ptr = const_cast<int*>(ci_ptr);    *i_ptr = 20; // 现在可以修改值    std::cout << "ci: " << ci << std::endl; // 输出可能是 20,也可能还是 10    std::cout << "*i_ptr: " << *i_ptr << std::endl; // 输出 20    return 0;}

                    09  

                      extern void Fun(DerivedClass* pd); void Gun(BaseClass* pb) //不好的例子: C风格强制转换,转换会导致对象布局不一致,编译不报错,运行时可能会崩溃DerivedClass* pd = (DerivedClass *)pb; //好的例子: C++风格强制转换,明确知道pb实际指向DerivedClass DerivedClass* pd = dynamic_cast< DerivedClass *>(pb); if(pd) Fun(pd);}

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

                      如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

                      相关文章

                      从零构建一款开源在线客服系统:我的Go语言实战之旅

                      了解更多&#xff0c;搜索 "程序员老狼"用代码连接世界&#xff0c;让沟通无界限缘起&#xff1a;为什么选择开发客服系统&#xff1f;在数字化浪潮席卷全球的今天&#xff0c;企业与客户之间的沟通方式正在发生深刻变革。传统的电话和邮件支持已无法满足即时互动的需…

                      unsloth笔记:基本介绍

                      更快的速度、更省的内存训练、运行、评估大模型 1 支持的模型 All Our Models | Unsloth Documentation 1.1 Dynamic GGUF/instruct 4-bit llama.cpp使用的新模型格式&#xff0c;专为高效、本地推理设计注&#xff1a;GGUF无法微调 只保留推理所需的内容&#xff0c;如量化…

                      博众测控 | 一文看懂菊水电源产品在半导体测试中的应用

                      01 半导体在各行业上的应用半导体作为现代工业体系的“核心神经”&#xff0c;其性能参数与应用场景深度绑定&#xff0c;不同行业因核心设备的功能需求差异&#xff0c;对半导体的电流、电压承载能力及类型选择有着明确且严格的要求&#xff0c;具体应用细节如下&#xff1a;1…

                      【STM32】贪吃蛇 [阶段 8] 嵌入式游戏引擎通用框架设计

                      这篇博客是 承接&#xff1a;【项目思维】贪吃蛇&#xff08;嵌入式进阶方向&#xff09;中 嵌入式游戏引擎雏形&#xff08;终极进阶&#xff09;&#xff0c; 是我们此前从 “写一个小游戏”提升到“构建可复用游戏框架” 的飞跃阶段。我们以“贪吃蛇游戏”为例&#xff0c;抽…

                      Vue图标按钮好用的样式

                      图标按钮示例一 <template><div class"icon-button-group"><button class"icon-btn icon-btn--default"><i class"el-icon-moon"></i></button><button class"icon-btn icon-btn--primary"&g…

                      Nginx 实战系列(一)—— Web 核心概念、HTTP/HTTPS协议 与 Nginx 安装

                      文章目录前言一、Web 概念1.1 Web 的基本概念1.1.1 Web的特点1.2 B/S 架构模型1.3 Web 请求与响应过程&#xff08;重点&#xff09;1.4 静态资源与动态资源1.5 Web 的发展阶段1.6 案例&#xff1a;搭建最小 Web 服务1.6.1 目标1.6.2 搭建步骤1.7 小结二、HTTP 与 HTTPS 协议2.…

                      一种用geoserver发布复杂样式矢量服务的方法

                      最近因为系统需要在国产系统中部署&#xff0c;遇见了国产系统不支持ArcGIS的尴尬局面&#xff0c;好在geoserver还是可以支持的&#xff0c;遂用geoserver解决服务问题。 在发布过程中&#xff0c;遇到比较难受的点就是矢量数据的样式配图&#xff0c;在我用QGIS配好导出sld后…

                      为什么神经网络网络算法比机器学习模型算法更加强大?

                      神经网络&#xff08;尤其是深度神经网络&#xff09;相比传统机器学习模型&#xff08;如线性回归、决策树、支持向量机等&#xff09;的“强大”主要体现在其更强的表达能力、自适应特征学习能力以及对复杂模式的建模能力。但这种“强大”并非绝对&#xff0c;而是有特定条件…

                      中国移动浪潮云电脑CD1000-系统全分区备份包-可瑞芯微工具刷机-可救砖

                      中国移动浪潮云电脑CD1000-系统全分区备份包-可瑞芯微工具刷机-可救砖 开启ADB教程&#xff1a; 可查看&#xff1a;浪潮CD1000-移动云电脑-RK3528芯片-232G-安卓9-开启ADB ROOT破解教程 可轻松打开了wifi adb和USB调试。 往期详细内容-文章&#xff1a;浪潮CD1000-移动云电脑…

                      C++两个字符串的结合

                      这段代码实现字符串拼接功能。用户输入两个字符串a和b后&#xff0c;使用append()方法将b追加到a后面&#xff0c;然后输出拼接后的结果。代码简洁但存在改进空间&#xff1a;1. 缺少输入验证 2. 直接修改原字符串a可能不符合某些场景需求 3. 可考虑更高效的拼接方式。适合基础…

                      UE4 Rider调试时添加自定义命令行参数

                      1、打开 Rider 右上角&#xff0c;针对你的项目&#xff08;例如叫做“Mini”&#xff09;打开 Edit 2、输入自定义的参数&#xff0c;如下图的例子是输入 -dx12 -norhithread &#xff0c;然后Apply并OK。3、开始调试&#xff08;虫子按钮&#xff09;

                      混合架构大型语言模型(Jamba)

                      Jamba是由AI21 Labs开发的混合架构大型语言模型&#xff08;LLM&#xff09;&#xff0c;结合了Transformer的语义理解能力和Mamba结构化状态空间模型&#xff08;SSM&#xff09;的高效性&#xff0c;旨在解决长文本处理中的计算瓶颈。 一、技术特点 1.混合架构设计 Jamba采用…

                      2025 年高教社杯全国大学生数学建模竞赛C 题 NIPT 的时点选择与胎儿的异常判定详解(一)

                      基于胎儿Y染色体浓度的孕周与BMI建模分析摘要本文利用某竞赛提供的胎儿Y染色体浓度数据&#xff0c;建立了以孕周和孕妇BMI为自变量的多项式回归模型&#xff0c;探讨了其对Y染色体浓度的影响。通过数据清洗与筛选&#xff0c;共获得1082条有效男胎样本。结果显示&#xff1a;Y…

                      PyTorch DDP 随机卡死复盘:最后一个 batch 挂起,NCCL 等待不返回

                      PyTorch DDP 随机卡死复盘&#xff1a;最后一个 batch 挂起&#xff0c;NCCL 等待不返回&#xff0c;三步修复 Sampler & drop_last很多人在接触深度学习的过程往往都是从自己的笔记本开始的&#xff0c;但是从接触工作后&#xff0c;更多的是通过分布式的训练来模型。由于…

                      计算机专业考研备考建议

                      对于全国硕士研究生招生考试&#xff08;考研&#xff09;&#xff0c;考试科目主要由两大部分组成&#xff1a;全国统一命题的公共课 和 由招生单位自主命题的专业课。具体的考试科目取决于你报考的专业和学校。下面我为你详细拆解&#xff1a;一、考试科目构成&#xff08;绝…

                      关于嵌入式学习——单片机1

                      基础整体概念以应用为中心:消费电子(手机、蓝牙耳机、智能音响)、医疗电子(心率脉搏、呼吸机)、无人机(大疆D)、机器人(人形四足机器人) 计算机技术:计算机五大组成:运算器(数据运算)、控制器(指令控制)、存储器(内存外存)、输入设备(鼠标、键盘、摄像头)、输出设备(显示器)软件…

                      LightDock.server liunx 双跑比较

                      LightDock: a new multi-scale approach to protein–protein docking The LightDock server is free and open to all users and there is no login requirement server 1示例 故去除约束 next step 结果有正有负合理 2.常见警告⚠ Structure contains HETATM entries. P…

                      SQL面试题及详细答案150道(61-80) --- 多表连接查询篇

                      《前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。 前后端面试题-专栏总目录 文章目录 一、本文面试题目录 61. 什么是内连接(INNE…

                      【实操】Noej4图数据库安装和mysql表衔接实操

                      目录 一、图数据库介绍 二、安装Neo4j 2.1 安装java环境 2.2 安装 Neo4j&#xff08;社区版&#xff09; 2.3 修改配置 2.4 验证测试 2.5 卸载 2.6 基本用法 2.7 windows连接服务器可视化 三、neo4j和mysql对比 3.1 场景对比 3.2 Mysql和neo4j的映射对比 3.3 mys…

                      【mysql】SQL查询全解析:从基础分组到高级自连接技巧

                      SQL查询全解析&#xff1a;从基础分组到高级自连接技巧详解玩家首次登录查询的多种实现方式与优化技巧在数据库查询中&#xff0c;同一个需求往往有多种实现方式。本文将通过"查询每个玩家第一次登录的日期"这一常见需求&#xff0c;深入解析SQL查询的多种实现方法&a…