C++编程不良习惯及改进方案教程
本文将列举C++开发中常见的十种不良编程习惯,无论新手还是资深开发者都可能沾染,并提供相应的修正方法。
一、变量未初始化
不良表现:定义变量时不给初始值,直接使用未定义的变量。例如:
cpp
int a, b, c; // 后续代码直接使用a、b、c
此时变量的值是不确定的(包含残留数据),程序行为不可预测。
正确做法:在变量定义时立即初始化。整数赋0,浮点数赋0.0,布尔赋false,指针赋nullptr。对于自定义类型,确保构造函数完成初始化。
二、命名不规范
不良表现:使用无意义的单字母命名(如a、b、c),或使用拼音、不准确的英文单词。例如用sex和boy/girl表示性别及男女,而非更专业的gender和male/female。
正确做法:
-
使用有意义的英文单词或词组
-
遵循项目统一的命名风格(驼峰、下划线等)
-
不熟悉的词汇借助翻译工具,但需确认准确性
-
常见规范:变量名小写字母开头(如
studentCount),类型名大写字母开头(如StudentInfo),常量全大写(如MAX_SIZE)
命名准确性需要长期积累,但值得投入时间。
三、变量声明位置与使用范围不匹配
不良表现:变量在很外层作用域声明,却只在内部小范围使用。例如:
cpp
int temp;
while (condition) {
temp = ...;
// 使用temp
}
变量temp被声明在循环外,但其有效使用范围仅在循环体内。
正确做法:将变量的声明移至最接近其使用位置的地方。上述代码应将temp声明在while循环内部。这样做的好处是:
-
提高代码可读性,读者无需上下查找变量定义
-
缩小变量作用域,减少误用的风险
-
便于重构和移动代码块
四、类成员数据未初始化
不良表现:类的默认构造函数未对成员变量进行初始化。例如:
cpp
class Point {
int x, y;
public:
Point() {} // x和y未初始化
};
创建Point对象后,x和y的值不确定,后续使用可能导致逻辑错误。
改进一:使用构造函数初始化列表
cpp
Point() : x(0), y(0) {}
但成员较多时容易遗漏。
正确做法(C++11起):在成员声明处直接赋予默认值
cpp
class Point {
int x = 0;
int y = 0;
};
这样无论调用哪个构造函数,成员都有确定的初始值,且不易遗漏。
五、使用裸指针管理动态内存
不良表现:手动new和delete动态对象,可能因提前返回、异常抛出等路径导致内存泄漏。例如:
cpp
void func() {
Point* p = new Point();
if (some_condition) return; // 内存泄漏
delete p;
}
正确做法:使用智能指针(C++11起)
-
std::unique_ptr:独占所有权,轻量高效 -
std::shared_ptr:共享所有权,引用计数 -
std::weak_ptr:配合shared_ptr打破循环引用
推荐使用std::make_unique(C++14)和std::make_shared创建智能指针,异常安全且更高效。
六、包含不必要的头文件
不良表现:代码中包含了从未使用的头文件,尤其常见的是图省事使用万能头文件#include <bits/stdc++.h>。这会引入大量标准库符号,显著增加编译时间。
正确做法:
-
只包含实际用到的头文件,例如使用
std::vector则包含<vector> -
在头文件中尽量使用前置声明而非包含其他头文件,减少编译依赖
-
使用工具(如Include What You Use)分析并清理冗余头文件
七、函数体过于庞大
不良表现:单个函数包含数百行甚至上千行代码,内部嵌套多层循环和条件分支,难以阅读和维护。
正确做法:
-
保持函数体在100行以内(理想情况50行)
-
一个函数只做一件事(单一职责原则)
-
将长函数拆分为多个小函数,每个小函数有清晰的名称和职责
-
使用辅助函数提取重复代码块
大型函数往往是代码坏味道的信号,应主动重构。
八、命名空间污染
不良表现:在全局作用域使用using namespace std;,或在头文件中使用using namespace。这会将标准库中的所有名称引入当前作用域,容易与自定义名称冲突。
典型错误:
cpp
#include <iostream> using namespace std; // 污染全局
另一个常见问题:自定义的变量、函数、类没有放入任何命名空间,全部暴露在全局。
正确做法:
-
去掉
using namespace std;,改用std::cout、std::vector等前缀 -
在实现文件(.cpp)的局部范围内,可谨慎使用
using(如using std::cout;),但避免在头文件中使用 -
将自己的代码放入独立的命名空间,例如
namespace MyLib { ... }
九、滥用全局变量
不良表现:在程序中大量使用全局变量,用于在不同函数间传递状态。这种做法在C语言代码中常见,但C++中应极力避免。
问题:
-
全局变量破坏模块化,任何函数都可能修改它,导致程序状态难以追踪
-
多线程环境下,全局变量需要复杂的同步机制
-
代码可测试性差,单元测试难以隔离
正确做法:
-
优先使用局部变量和函数参数传递数据
-
需要跨多个函数共享的状态,可封装在类中作为成员变量
-
对于真正需要全局访问的配置信息,使用单例模式(但也要谨慎)或依赖注入
-
考虑将全局变量改为静态成员变量并合理限制访问权限
十、缺少必要的注释
不良表现:代码没有任何注释,尤其是一些算法复杂、逻辑非直观的函数。例如下面的函数,短短三行却让人费解:
cpp
int f(int a, int b) {
return (a & b) + ((a ^ b) >> 1);
}
很少有人一眼看出这是求两个整数的平均值(防止溢出的版本)。
正确做法:
-
为每个公开的函数添加注释:说明函数功能、参数含义、返回值、可能的异常
-
对复杂的算法或业务逻辑,在代码块上方添加解释性注释
-
不要注释“做了什么”,而是注释“为什么这么做”以及“注意事项”
-
保持注释与代码同步更新,过时的注释比没有注释更糟
好的注释能让代码自解释,提高团队协作效率。
补充说明:坏习惯的改正需要刻意练习
以上十大坏习惯,很多开发者并非不知道,而是缺乏改正的意识和决心。以下是几点建议:
-
使用静态分析工具:如Clang-Tidy、Cppcheck,能自动检测未初始化变量、未使用的头文件等问题。
-
代码审查:请同事审查代码,他们更容易发现你习以为常的坏习惯。
-
逐步改进:每次修改代码时,顺手把涉及到的坏习惯改正,不必一次性重写所有代码。
-
学习优秀开源代码:阅读Boost、LLVM等高质量C++项目,观察其命名、注释、作用域控制等细节。
总结与自查清单
为了让读者更容易对照检查,以下列出十个坏习惯的速查表:
-
变量定义时是否给了初始值?
-
变量名是否有意义且准确(非拼音、非单字母)?
-
变量的作用域是否尽可能小?
-
类的成员变量是否在声明处有默认值?
-
动态内存管理是否使用了智能指针而非裸指针?
-
头文件是否只包含必要的内容?是否用了万能头文件?
-
函数体是否超过100行?是否需要拆分?
-
是否在头文件或全局使用了
using namespace? -
是否存在不必要的全局变量?
-
关键函数和复杂逻辑是否有清晰的注释?
建议每完成一个模块的编码,对照此清单自查一次,逐步养成良好的编程习惯。
进阶思考:从坏习惯到代码质量文化
坏习惯往往是“省事”心态的产物。初学者为了快速看到效果而忽略规范,久而久之形成肌肉记忆。打破这些习惯,需要将编码规范内化为本能。
一些团队采用格式化工具(clang-format)和静态检查(pre-commit钩子)强制约束,例如:
-
自动格式化代码风格
-
禁止提交包含未初始化变量的代码
-
检查头文件包含是否冗余
另外,可以尝试“童子军规则”:每次修改一个文件时,顺便改善其中的一两个小问题(如补充注释、缩小作用域)。随着时间推移,整个代码库的质量会逐步提升。
结语
C++是一门强大但复杂的语言,它给予程序员极大的控制权,同时也要求程序员承担相应的责任。上述十大坏习惯,有些是C/C++特有的(如裸指针、未初始化变量),有些是所有编程语言共通的(如命名、注释)。
改正坏习惯不是一蹴而就的。我曾经花数年时间才彻底改掉某个不良编码风格。但只要你有意识地每天改进一点点,代码质量就会稳步上升。希望这份清单能帮助你少走弯路,写出更健壮、更可维护的C++代码。
本教程纯技术分享,无任何广告或推广内容。
更多推荐


所有评论(0)