C++之美:代码整洁、安全又跑得快的30个要诀(好书推荐)

news2024/11/17 15:55:55

在编程领域,C++ 以其高效性和灵活性著称,但同时也因其复杂性和易出错性而闻名。如何写出既整洁、又安全且高效的 C++ 代码,是每个 C++ 开发者都需要思考的问题。《C++之美:代码整洁、安全又跑得快的30个要诀》这本书为我们提供了宝贵的指导。本文将基于这本书的核心内容,分享其中的精华,帮助大家提升 C++ 编程水平。

前言

C++ 是一门历史悠久且功能强大的编程语言,广泛应用于系统开发、游戏引擎、高性能计算等领域。然而,C++ 的复杂性也给开发者带来了不少挑战。本书通过总结和提炼了30个实用的编程要诀,帮助读者写出既整洁、又安全且高效的 C++ 代码。

《C++之美:代码简洁、安全又跑得快的30个要诀》从《C++核心准则》(C++ Core Guidelines)中精心挑选了30条准则进行细致、深入的讲解。内容涵盖C++语言最主要的方面,如类型系统、面向对象、模板和元编程、错误处理、程序性能、常量性等,其间又恰如其分地穿插了编码风格、设计模式等主题。书中汇集了作者数十年职业生涯的经验和一些有趣的示例,除了深刻的见解,行文也充满了趣味性。作者试图通过这种突出重点、以点带面的方式帮助读者了解并学习《C++核心准则》,进而更深入地掌握C++这门编程语言,特别是它的“现代”形态。本书适合各种水平的C++开发者阅读。

作者简介

J. Guy Davidson于1980年通过Acorn Atom首次接触编程。他青少年时代的大部分时间都在各种家用电脑上编写游戏。后来,他从苏塞克斯大学获得了数学学位,开始涉足戏剧,还在一个灵魂乐队中担任键盘手。20世纪90年代初,他决定编写演示程序,并于1997年开始在Codemasters的伦敦办公室工作,从此进入游戏行业。1999年,Davidson加入了Creative Assembly,现在是那里的工程实践主管。他主要负责《全面战争》(Total War)系列游戏的工作,整理早期的游戏目录,以及提升工程团队成员的编程水平。他是IGGI咨询委员会、BSI C++小组和ISO C++委员会的委员,还是ACCU(Association of C/C++ Users,C/C++用户协会)负责C++标准相关事宜的成员,并在ACCU的编程委员会任职。

核心要诀概览

本书围绕着“整洁、安全、高效”三个核心主题,详细介绍了30个编程要诀。

以下是其中的一些关键点:

1.整洁

代码风格统一:遵循一致的代码风格规范,如命名规则、缩进、注释等。

简洁表达:尽量使用简洁的表达式和函数,避免冗余代码。

模块化设计:将代码分解成可重用的模块,提高代码的可维护性。

最小作用域:变量应在最晚可能的时间声明,在最早不被使用后销毁,减少潜在的副作用和内存占用。

函数单一职责:每个函数应该只有一个明确的任务,这样做不仅使得代码易于理解,也便于测试和维护。

2.安全

内存安全:避免使用原始指针,尽量使用智能指针(如 std::unique_ptr 和 std::shared_ptr)。

资源管理:遵循 RAII(Resource Acquisition Is Initialization)原则,确保资源的正确释放。(如文件句柄、数据库连接)在对象生命周期结束时自动释放。

异常安全:编写异常安全的代码,确保在异常情况下也能正确释放资源。确保资源管理和状态保持一致。

3.高效

性能优化:理解 C++ 标准库的性能特性,合理使用标准库函数。

编译优化:利用现代编译器的优化选项,提高代码的执行效率。

并发编程:合理使用多线程和并发编程技术,提高程序的并发性能。

具体要诀详解

1. 代码风格统一

命名规范:采用一致的命名规范,如 camelCase 或 snake_case。

缩进和空格:使用一致的缩进和空格,提高代码的可读性。

注释:为重要的代码段添加注释,说明代码的功能和意图。

确保不同模块和函数之间的风格和设计一致,可以增强团队的协作性,降低维护成本。

2. 简洁表达

使用范围for循环:使用 for (auto& item : container) 来遍历容器,简洁且不易出错。

    std::vector<int> numbers = {1, 2, 3};
    for (auto& num : numbers) {
        std::cout << num << " ";
    }
    

使用lambda表达式:使用 lambda 表达式简化回调函数的定义。

 std::sort(numbers.begin(), numbers.end(), [](int a, int b) { return a > b; });
    

避免冗余代码:尽量复用已有代码,避免重复编写相同的逻辑。

    template<typename T>
    void print(T value) {
        std::cout << value << std::endl;
    }
    

3. 模块化设计

分离接口和实现:将接口和实现分离,提高代码的可维护性和可扩展性。

使用头文件和源文件:将类的声明放在头文件中,实现放在源文件中。

合理组织代码结构:按照功能模块组织代码,提高代码的可读性和可维护性。

限制命名空间:尽量避免使用全局命名空间,限制变量和函数的作用域,可以减少命名冲突的几率。

    src/
    ├── my_class.h
    ├── my_class.cpp
    └── utils.h
    
    // my_class.h
    class MyClass {
    public:
        void doSomething();
    };

    // my_class.cpp
    #include "my_class.h"

    void MyClass::doSomething() {
        // 实现细节
    }
    

接口设计:清晰定义接口,隔离实现细节,促进模块间的松耦合。

模板编程:通过泛型编程实现类型无关的代码复用,提升代码的通用性和灵活性。 

4. 内存安全

使用智能指针:使用 std::unique_ptr 和 std::shared_ptr 管理动态分配的内存,避免内存泄漏。

std::unique_ptr<MyClass> ptr(new MyClass());
    
std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>();
MyClass* rawPtr = ptr.get();  // 使用智能指针获取原始指针
    

避免野指针:确保指针始终指向有效的对象,避免使用已删除的对象。

使用RAII:通过 RAII 技术管理资源,确保资源在对象生命周期结束时自动释放。

    class Resource {
    public:
        Resource() { /* 初始化资源 */ }
        ~Resource() { /* 释放资源 */ }
    };

    void someFunction() {
        Resource resource;  // RAII
    }
    

空指针和边界检查:在使用指针或数组时,务必进行空指针和边界检查,以避免程序崩溃。 

5. 资源管理

使用RAII:通过 RAII 技术管理资源,确保资源在对象生命周期结束时自动释放。

避免资源竞争:合理使用锁机制,避免资源竞争导致的死锁或竞态条件。

    std::mutex mutex;

    void someFunction() {
        std::lock_guard<std::mutex> lock(mutex);
        // 执行临界区代码
    }
    

资源池技术:使用资源池技术管理大量相似资源,提高资源的利用率。

    class ResourcePool {
    public:
        Resource getResource() {
            std::lock_guard<std::mutex> lock(mutex);
            if (!available.empty()) {
                Resource res = available.front();
                available.pop();
                return res;
            }
            return Resource();
        }

        void releaseResource(Resource res) {
            std::lock_guard<std::mutex> lock(mutex);
            available.push(res);
        }

    private:
        std::queue<Resource> available;
        std::mutex mutex;
    };
    

6. 异常安全

异常安全的构造函数:确保构造函数在抛出异常时能够正确释放资源。

    class MyClass {
    public:
        MyClass() {
            try {
                // 初始化资源
            } catch (...) {
                // 清理资源
                throw;
            }
        }
    };
    

异常安全的析构函数:确保析构函数在抛出异常时能够正确释放资源。

    class MyClass {
    public:
        ~MyClass() {
            // 释放资源
        }
    };
    

异常安全的成员函数:确保成员函数在抛出异常时能够正确释放资源。

    class MyClass {
    public:
        void someFunction() {
            try {
                // 执行操作
            } catch (...) {
                // 清理资源
                throw;
            }
        }
    };
    

利用代码分析工具(如Clang-Tidy)可以帮助我们识别潜在问题,提高代码质量。 

7. 性能优化

理解标准库性能:了解标准库函数的内部实现,合理使用标准库函数。

    std::vector<int> numbers = {1, 2, 3};
    std::sort(numbers.begin(), numbers.end());
    

编译器优化:利用编译器的优化选项(如 -O3),提高代码的执行效率。

避免不必要的复制:使用移动语义(move semantics)减少不必要的复制。

    MyClass moveFunc(MyClass&& obj) {
        return std::move(obj);
    }
    

8. 并发编程

使用线程库:使用 std::thread 和 std::mutex 实现多线程编程。

使用原子操作:使用 std::atomic 类型保证数据的一致性。

合理使用线程池:使用线程池技术管理线程资源,提高并发性能。

对于轻量级同步,优先考虑使用std::atomic;对于复杂场景,选用适当的锁机制,如std::mutex或更高级的锁。

避免数据竞争:设计线程安全的数据结构,确保多线程访问数据时的一致性和完整性。

在多线程编程中,注意数据共享和线程安全的问题。使用C++11的std::mutex等同步机制可以有效防止数据竞争。

总结

通过学习《C++之美:代码整洁、安全又跑得快的30个要诀》,我们可以更好地理解和掌握 C++ 的核心编程技巧。无论是初学者还是经验丰富的开发者,都可以从中受益匪浅。希望本文的分享能帮助大家提升 C++ 编程水平,写出更加优秀和可靠的代码。

写在最后

最后,推荐下笔者的业余开源app影视项目“爱影家”,推荐分享给与我一样喜欢观影的朋友。

开源地址:爱影家app开源项目介绍及源码

其他资源

https://book.douban.com/subject/36962341/

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

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

相关文章

git clone代码报错Permission denied (publickey)

git clone gerrit SSH的Clone with commit-msg hook代码连接&#xff0c;报错Permission denied (publickey). 一般在C:\Users\用户名.ssh文件夹下有一个id_rsa.pub文件 把文件里的内容复制 到gerrit网站上User Settings的SSH keys里 在New SSH key里粘贴刚刚复制的内容&…

【递归】6.LPC 44 开幕式火焰

1 题目描述 题目链接&#xff1a;开幕式火焰 2 解答思路 递归分为三步&#xff0c;接下来就按照这三步来思考问题 第一步&#xff1a;挖掘出相同的子问题 &#xff08;关系到具体函数头的设计&#xff09; 第二步&#xff1a;只关心具体子问题做了什么 &#xff08;关系…

那些年我和 ChatGPT 合谋摸鱼的日子

文章目录 那些年我和 ChatGPT 合谋摸鱼的日子1 序个言2 说正事3 这次是真正的正事4 总个结 那些年我和 ChatGPT 合谋摸鱼的日子 1 序个言 看到 CSDN 出这个活动有段时间了&#xff0c;奈何俗务缠身&#xff0c;一直没静下心来想想怎么写。今天碰巧赶上了&#xff0c;就顺便聊聊…

【Linux扩容根分区】LVM分区扩容过程踩坑记录

最近想要给自己使用的Linux操作系统的根分区进行扩容&#xff0c;解决完发现&#xff0c;原来问题如此简单。 特此记录&#xff0c;希望能帮助到有需要的人。 通过df -Th查看系统磁盘分区情况 通过vgdisplay 查看内容 实操过程中&#xff0c;原来红框中&#xff0c;Free PE …

2024年双十一买啥最划算?双十一好物推荐闭眼入!

一年一度的双十一购物狂欢节已悄然临近&#xff0c;这不仅是一场消费者的盛宴&#xff0c;更是各大品牌竞相展示实力、推出优惠的绝佳时机。在这个全民狂欢的日子里&#xff0c;数码产品作为科技与生活的桥梁&#xff0c;相信已经有不少朋友想要大买特买了。无论是追求极致性能…

《python语言程序设计》2018版第8章18题几何circle2D类(下部)

前言、从9.20激动发言到现在一直没有克制住的心情中,回到编程 比如删掉我设计的导入第二个园的x,y,radius的函数我做了之前设计的变化.建立了两个可以将x,y拿出来的函数out计算两个坐标之间的距离利用已知的两个坐标之间的距离来比对第1个园里的半径,看第2个园的坐标是否在第一…

Linux文本内容管理命令_2

find&#xff1a;-查找命令执行文件 which 命令 whereis 命令 type 命令----查看命令类型 alias &#xff08;命令别名&#xff09; cat 查看文件--更新文件时间&#xff0c;再次cat&#xff0c;时间不会改变 touch--会更新所有属性的时间&#xff0c;文件诞生时间不会改变 …

求n的阶乘的相反数(c语言)

1./请编写函数fun&#xff0c;其功能是:计算并输出下列多项式的值: // s11/1!1/2!1/3!1/4!1/5!1/6!1/7!...1/n! //例如&#xff0c;在主函数中从键盘给n输入15&#xff0c;则输出为:s 2.718282。 //注意:要求n的值大于1但不大于100。 2.我们先输入数字n,然后先讲n!的阶乘计算…

NMOS的原理

NMOS&#xff08;N型金属氧化物半导体场效应晶体管&#xff09;是常见的场效应晶体管&#xff08;FET&#xff09;的一种&#xff0c;其主要电极包括D极&#xff08;Drain&#xff09;、S极&#xff08;Source&#xff09;和G极&#xff08;Gate&#xff09;&#xff0c;每个电…

JavaSE——lombok、juint单元测试、断言

一、lombok的使用 默认jvm不解析第三方注解&#xff0c;需要手动开启 链式调用 二、juint单元测试 下载juint包 public class TestDemo {// 在每一个单元测试方法执行之前执行Beforepublic void before() {// 例如可以在before部分创建IO流System.out.println("befor…

【数据结构】栈和队列(Stack Queue)

引言 在对顺序表&#xff0c;链表有了充分的理解之后&#xff0c;现在让我们学习栈和队列&#xff01;&#xff01;&#xff01; 【链表】 &#x1f448;链表 【顺序表】&#x1f448;顺序表 目录 &#x1f4af;栈 1.栈的概念及结构 2.栈的实现 ⭐初始化栈 ⭐入栈 ⭐…

【C++】入门基础知识-1

&#x1f36c;个人主页&#xff1a;Yanni.— &#x1f308;数据结构&#xff1a;Data Structure.​​​​​​ &#x1f382;C语言笔记&#xff1a;C Language Notes &#x1f3c0;OJ题分享&#xff1a; Topic Sharing 目录 前言&#xff1a; C关键字 命名空间 命名空间介…

【论文翻译】AFLGuard: Byzantine-robust Asynchronous Federated Learning

提示&#xff1a;该论文标题为AFLGuard: Byzantine-robust Asynchronous Federated Learning&#xff0c;我将对其进行部分翻译&#xff0c;便于后续阅读。 文章目录 AFLGuard&#xff1a;拜占庭鲁棒的异步联邦学习一、摘要二、引言三、知识前提拜占庭鲁棒联邦学习 四、问题表述…

JVM(HotSpot):程序计数器(Program Counter Register)

文章目录 一、内存结构图二、案例解读三、工作流程四、特点 一、内存结构图 二、案例解读 我们使用javap对字节码进行反编译&#xff0c;来看下程序计数器怎么体现的。 IDEA写一个简单的Java代码 反编译命令 javap -verbose InitTest.class $ javap -verbose InitTest.clas…

解决Typora图片复制到CSDN无法查看问题

下载安装picgo 山东大学镜像源&#xff1a;https://mirrors.sdu.edu.cn/github-release/Molunerfinn_PicGo 开通阿里云对象存储oss 选择创建 填入内容 购买资源包 创建AccessKey 配置PicGo 设定bucket填入创建bucket名称 注意&#xff1a;设定存储区域只需要填写到区域前缀即…

变电站设备检测系统源码分享

变电站设备检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer V…

C++ 继承:打破代码冗余,提升开发效率

目录 继承的概念和定义 继承的概念 继承的定义 定义格式 继承关系和访问限定符 继承基类成员访问方式的变化 基类和派生类对象赋值转换 继承中的作用域 派生类的默认成员函数 构造函数 拷贝构造 赋值运算符重载 析构函数 继承与友元 继承与静态成员 菱形继承与…

数据库——sql语言学习 查找语句

一、什么是sql SQL是结构化查询语言&#xff08;Structured Query Language&#xff09;的缩写&#xff0c;它是一种专门为数据库设计的操作命令集&#xff0c;用于管理关系数据库管理系统&#xff08;RDBMS&#xff09;。 二、查找相关语句 ‌‌首先&#xff0c;我们已经设…

【SQL】筛选字符串与正则表达式

目录 语法 需求 示例 分析 代码 语法 SELECT column1, column2, ... FROM table_name WHERE condition; WHERE 子句用于指定过滤条件&#xff0c;以限制从数据库表中检索的数据。当你执行一个查询时&#xff0c;WHERE 子句允许你筛选出满足特定条件的记录。如果记录满…

计算计的风向标大转!计算机专业的新纪元已至!

亲爱的读者们&#xff0c; 在这个科技日新月异的时代&#xff0c;计算机专业正以前所未有的速度引领着行业的变革。从传统编程到人工智能、大数据、云计算等新兴技术的崛起&#xff0c;计算机专业的学习与发展路径正经历着翻天覆地的变化。今天&#xff0c;让我们一同探索这个…