高质量C++编程补充条款

简介: 文件:高质量C++编程补充条款.pdf大小:169KB下载:下载目录1. 前言 12. 条款:避免使用非众所周知的缩略语 13. 条款:规范好#include 14.
文件: 高质量C++编程补充条款.pdf
大小: 169KB
下载: 下载

目录

1. 前言

介绍高质量 C++ 编程的书籍很多,而且都非常好,这里主要针对已有书籍较少涉及到的代码格式条款进行补充。代码是程序员脸面,清清爽爽和干干净净的代码是程序员高职业素质的体现,清爽的代码需要从细节做起,用心呵护。

2. 条款:避免使用非众所周知的缩略语

本条款非新鲜的,但实际很少有人真正遵循,在代码中总能见到一些自创的缩略语,后来接手代码的人常常需要去猜测是啥意思。因此提出来重点强调一下,如: GeneralServer ,不要写成 CGSConfig ,而应当使用长名 CGeneralServerConfig ,长名是自注释的,前者在上下文环境不足和缺少文档的情况(除了华为那样文档要求非常严格的企业,可能一般公司都存在这样的情况)下可能需要去猜测。

3. 条款:规范好#include

#include 也有讲究,通常 在前, "" 在后,如:
#include 
#include "mooon.h"
而且非隶属本编译工程中的头文件,一律使用 ,隶属本编译工程中的头文件使用 ""

4. 条款:避免长短语句无规律交错

下面这段代码无规律的交错着,容易给人以混乱的感觉:
void reset_current_message(bool finish);
void free_current_message();
void inc_resend_times();    
util::handle_result_t do_handle_reply(); 
void clear_message();               
net::epoll_event_t do_send_message(void* ptr, uint32_t events);
使用这一条款后,变成成如下:
    void clear_message();    
    void inc_resend_times();      
    void free_current_message();
    void reset_current_message(bool finish);
    util::handle_result_t do_handle_reply();            
    net::epoll_event_t do_send_message(void* ptr, uint32_t events);
从短到长,明显清爽清晰了很多,变量了定义等也应当尽量遵守此条款。
#include 段也应当尽量遵循这个规律,如:
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "sys/fs_util.h"
#include "sys/close_helper.h"
如果一些变量是相关的,则可以使用空行分开,在同一组内实施这一条款。

5. 条款:避免头重脚轻

char* str = get_value("thread_number");
if (str != NULL)
{
thread_number = string2int(str);
if (0 == thread_number)
_thread_number = 1;
else
_thread_number = thread_number;
}
else
{
_thread_number = 1;
}
上面的代码段,就显得头重脚轻, if 块比 else 块大了很多。特别是当 if 块超过 50 行时,会导致 else 块较难看,甚至可能难以一下确定 else 对应哪个 if 语句。将两者跌倒一下,就可以消除头重脚轻的问题,如下:
char* str = get_value("thread_number");
if (NULL == str)
{
_thread_number = 1;
}
else
{
thread_number = string2int(str);
if (0 == thread_number)
_thread_number = 1;
else
_thread_number = thread_number;
}

6. 条款:充分利用publicprivate

C++ 允许 public 等修饰符在一个类的定义中多次重复出现,充分利用这一特性,可使得类的定义代码变得更清爽。下面这段代码充分利用了这一特性,对类的定义进行了归类,使得整个定义显得较为清爽不凌乱交错:
class CSender: public net::CTcpClient
{   
public: //  公有函数
    ~CSender();
    CSender(CSendThreadPool* thread_pool, int32_t route_id, uint32_t queue_max, IReplyHandler* reply_handler);
    
    int32_t get_node_id() const;       
    bool push_message(dispatch_message_t* message, uint32_t milliseconds);    
public: //  公有的虚拟函数
virtual void after_connect();
private: //  重写的虚拟函数
    virtual void before_close();
    virtual void connect_failure();
    
private: //  非重写的私有函数
    void clear_message();    
    void inc_resend_times();      
    void free_current_message();
    void reset_current_message(bool finish);
    util::handle_result_t do_handle_reply();            
    net::epoll_event_t do_send_message(void* ptr, uint32_t events);
    
protected: //  提供给不同子类使用的公共函数
    void do_set_resend_times(int8_t resend_times);
    net::epoll_event_t do_handle_epoll_event(void* ptr, uint32_t events);
       
private: //  非状态成员
    int32_t _route_id;    
    CSendQueue _send_queue;        
    IReplyHandler* _reply_handler;
    CSendThreadPool* _thread_pool;
private: //  发送状态相关的
    int8_t _cur_resend_times;  //  当前已经连续重发的次数
    int8_t _max_resend_times; //  失败后最多重发的次数,负数表示永远重发, 0 表示不重发
    uint32_t _current_offset;             //  当前已经发送的字节数
    dispatch_message_t* _current_message; //  当前正在发送的消息
};

7. 条款:类成员优先使用对象类型

按照 UML 上的术语来说,就是优先使用组合,而非聚合,虽然从依赖性上讲聚合低于组合,但这只是理论上,对于一个对象的生命周期由别一个类来掌握时,使用组合更好,原因是组合使得该类对象的内存空间连续,而聚合通常需要在构造函数中 new ,在析构中 delete ,容易造成更多的内存碎片,总是连续的比非连续的好,如:
class CAgentThread
{
private:
CMasterConnector _connector; //  建议使用对象类型
};
当然如果只是关联关系,那肯定只能使用指针类型了,如:
class CAgentThread
{
private:
CAgentContext* _contexnt; //  只能使用指针类型
}

8. 条款:名字空间的使用

杜绝在头文件使用 using ,包括 using namespace std using std::vector 两种形式。这样做完全失去了名字空间的意义,减少名字间的冲突。

9. 条款:巧用do...while(false)替代goto

先看下段代码:
int CTcpClient::timed_connect()
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == fd)
{
return errno; // goto CONNECT_ERROR:
}
if (-1 == connect(fd, peer_addr, addr_length))
{
close(fd);
return errno;
}
if (!CNetUtil::timed_poll(fd, POLLIN | POLLOUT | POLLERR, _milli_seconds))
{
close(fd);
return errno;
}
if (-1 == getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &errcode_length))
{
close(fd);
return errno;
}
set_fd(fd);
return 0;
}
上面这段代码,在出错的地方,有多处 return ,代码基本相同,通常大家会想到使用 goto 语句来解决这个问题。 goto 总是应当只作为最后不得已的一种选择,通过下面这段代码我们来看看如何使用 do...while(false) 优雅的解决这个问题:
int CTcpClient::timed_connect()
{
int fd = -1;
do
{
fd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == fd)
{
break; // goto CONNECT_ERROR:
}
if (-1 == connect(fd, peer_addr, addr_length))
{
close(fd);
break;
}
if (!CNetUtil::timed_poll(fd, POLLIN | POLLOUT | POLLERR, _milli_seconds))
{
close(fd);
break;
}
if (-1 == getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &errcode_length))
{
close(fd);
break;
}
set_fd(fd);
return 0;
}
while (false);
//  相当于 goto 到这里
if (fd != -1) close(fd);
return errno;
}
使用 do...while(false) 后,整个函数就只有两个 return 出口了。

10. 条款:利用typedef增强代码的自注释

在一些开源和 C++ 标准库 stl 中,可以见到大量的 typedef 使用,除了使用 typedef 来简化长类型的定义,如: typedef basic_string string; 外,还有增强代码自注释的目的。
假设需要一个存储 IP 端口号的列表,可以定义如下:
std::list port_list_t;

11. 条款:不要失去对进程和线程的控制权

在设计和代码中,应当杜绝时长未定或较长的 sleep 调用,以及完全阻塞的 accept/read 等调用,因为这会使你失去对进程和线程的控制权。当你需要进行死锁检测,将不容易区分,当程序需要退出,会比较麻烦。正确的做法是保证 sleep 的时间尽可能短而且最长时间明确,通常不要超过 10 秒,甚至可以考虑使用可唤醒的条件等替代,而 accept/read 应当改用带超时的,或使用非阻塞的,这样就能牢牢把握对进程和线程的控制权。


待续 。。。。。。
相关文章
|
23天前
|
安全 算法 C++
【C/C++ 泛型编程 应用篇】C++ 如何通过Type traits处理弱枚举和强枚举
【C/C++ 泛型编程 应用篇】C++ 如何通过Type traits处理弱枚举和强枚举
46 3
|
25天前
|
安全 算法 编译器
【C++ 泛型编程 进阶篇】深入探究C++模板参数推导:从基础到高级
【C++ 泛型编程 进阶篇】深入探究C++模板参数推导:从基础到高级
240 3
|
25天前
|
存储 算法 编译器
【C++ TypeName用法 】掌握C++中的TypeName:模板编程的瑞士军刀
【C++ TypeName用法 】掌握C++中的TypeName:模板编程的瑞士军刀
234 0
|
25天前
|
算法 编译器 数据库
【C++ 泛型编程 高级篇】使用SFINAE和if constexpr灵活处理类型进行条件编译
【C++ 泛型编程 高级篇】使用SFINAE和if constexpr灵活处理类型进行条件编译
243 0
|
25天前
|
设计模式 程序员 C++
【C++ 泛型编程 高级篇】C++模板元编程:使用模板特化 灵活提取嵌套类型与多容器兼容性
【C++ 泛型编程 高级篇】C++模板元编程:使用模板特化 灵活提取嵌套类型与多容器兼容性
241 2
|
2天前
|
编译器 C++
C++编程之美:探索初始化之源、静态之恒、友情之桥与匿名之韵
C++编程之美:探索初始化之源、静态之恒、友情之桥与匿名之韵
15 0
|
24天前
|
存储 移动开发 安全
【C/C++ 口语】C++ 编程常见接口发音一览(不断更新)
【C/C++ 口语】C++ 编程常见接口发音一览(不断更新)
21 0
|
24天前
|
算法 编译器 C++
【C++ 模板编程 基础知识】C++ 模板类部分特例化的参数顺序
【C++ 模板编程 基础知识】C++ 模板类部分特例化的参数顺序
21 0
|
24天前
|
机器学习/深度学习 人工智能 算法
【C++ 职业方向】C++ 职业方向探索:工作职责、编程技能与MBTI人格匹配
【C++ 职业方向】C++ 职业方向探索:工作职责、编程技能与MBTI人格匹配
157 1
|
24天前
|
安全 编译器 程序员
【C++ 泛型编程 高级篇】C++ 编程深掘:静态成员函数检查的艺术与实践
【C++ 泛型编程 高级篇】C++ 编程深掘:静态成员函数检查的艺术与实践
62 0