C++产品开发讲座-(一)编程规范

C++产品开发讲座-(一)编程规范

1. 编程风格

文件夹文件名:⼩写+下划线: demo_data_type.h
枚举类名:
enum class EnumDataType
{
    
    
 EnumDataTypeA,
 EnumDataTypeB
};
class,struct名:单词首字母大写
class DemoData
{
    
    
};
函数名:首字母小写,后面单词首字母大写
void procData(uint32_t index_pipeline);
变量名:全小写,单词之间加下划线
uint32_t num_buffer;//变量

2.注释

注释是法外之地
最好代码⾃注释(能通过代码变量命名、代码风格直接体现出编程逻辑最好)

3. 命名

(1)最大对其原则

同一类型,同一属性的变量、函数、枚举等,名称最好都按照相同的属性、类型对齐。

strcut School
{
    
    
 uint32_t index_grade;
 uint32_t index_class;
 uint32_t index_student;
 uint32_t index_teacher;
};
//index_开头

(2)常用命名前缀,后缀

// 指针
sp_ std::shared_ptr<DemoData> sp_xxx
p_ float* p_xxx
// 函数
procXXX
genXXX
// stl容器
vec_ std::vector<DemoData> vec_demo_data;
arr_ std::array<DemoData, N> arr_xxx
lut_ // look up table
map_ // tsd::map/std::unordered_map
// 其他常⽤
flag_
thread_ //thread
temp_ // 临时
param_ // parameter配置
struct/class ParamXXX //配置参数
cnt_ // counter
num_ // number num_buffer
len_ // length len_vec_data
index_ //index/id
name_ // 名称
msg_ // message
_info // information
val_xxx // value_xxx val_signal
type_xxx // type
// ui控件名
txt_ // textbox, txt_username
lb_ // label
dlg_ // dialog
win_ // windows

4. 编程要求

4.1 凡是有可能失败的函数均返回值为bool、具有资源申请相关的class具有返回值为bool的init

bool procPanMeasGeo(const cv::Mat& img);

原则上,构造函数不做任何可能失败的事情,可能失败的事情交由init函数

class DemoData
{
    
    
	public:
	 DemoData()
	 {
    
    
	 	p_data = new float[...](错误:不应再构造函数内申请内存)
	 }
	 bool init()
	 {
    
    
	 	p_data = new float[...](正确)
	 }
	private:
	 float* p_data;
}

4.2 任何资源都需要释放,任何运行时资源均需要停止,具有资源申请的类需具有可重入的close/stop函数并在析构时调用

资源申请均需要释放,malloc/free配对,new/delete配对,fopen/fclose配对
运⾏时资源std::thread,需if (thread.joinable()) thread.join() 结束线程资源
close(), stop()需可重入,即被调⽤多次也没有问题(如free指针前先判断nullptr,free后将指针置为
nullptr),因为⽤户可能主动调,也可被析构调⽤。

struct DemoData
{
    
    
	 ~DemoData()
	 {
    
    
	 	stop();
	 }
	 void stop()
	 {
    
    
	 	if (thread_proc.joinable()) thread_proc.join();
	 	if (p_data != nullptr)
	 	{
    
    
	 		free(p_data);
	 		p_data = nullptr;
	 	}
	 }
	 bool init()
	 {
    
    
	 	thread_proc = std::thread(...)
	 	p_data = (float*)malloc(1024);
	 	return p_data == nullptr;
	 }
	 std::thread thread_proc;
	 float* p_data;
}

4.3 原则上严禁在运⾏时new/malloc

原则上在init函数内预先开空间,运⾏时复⽤,运⾏时new/malloc非常消耗资源

4.4 整型变量不采用int,short等而采用uint32_t,int64_t

不同操作系统、硬件构架对int等数据类型的解释不同,其字节数不能确定,所以使用uint32_t等直接指定字节数。
<stdint.h>
int x;(x)
uint32_t, int64_t, uint8_t

4.5 严禁常量,常量采⽤宏或者枚举,枚举更优

严禁hardcode(字符串、数值写死)
枚举可读性佳

hardcode 写死
if (val_str == "key:") 不推荐
if (val_str == TAG_KEY_STR) 推荐
enum EnumDataType : uint32_t
{
    
    
	EnumDataTypeA = 0,
	EnumDataTypeB = 1
};
if (type == EnumDataType::ENumDataTypeA) 推荐
if (type == 0)// 0 is data type a 不推荐

4.6 采用do while(false),RAII避免遗漏

涉及多个资源步骤的流程,每个步骤可能失败,第i步失败需将前i-1次申请的资源全部释放将导致代码逻辑爆炸

不建议的写法
FILE* p_file = fopen(...)
if (p_file == nullptr) return -1;
uint8_t* p_buffer = malloc(...)
if (p_buffer == nullptr)
{
    
    
	fclose(p_file);
	return -1;
}
uint32_t size_read = xfread(p_file, p_buffer)
if (size_read == size)
建议的写法,在申请资源、打开文件失败后break,然后统一释放已申请的资源。
FILE* p_file = nullptr;
uint8_t* p_buffer = nullptr;
....
do
{
    
    
	 p_file = fopen(...)
	 if (p_file == nullptr) break;
	 p_buffer = malloc(...)
	 if (p_buffer == nullptr) break;
	 //...
}
while (false);
if (p_file != nullptr) fclose(...);
if (p_buffer != nullptr) free(p_buffer)...

采⽤RAII来避免遗忘,如加锁解锁配对、log进入log退出配对、资源申请资源释放配对。
RAII 是 resource acquisition is initialization 的缩写,意为“资源获取即初始化”。它是 C++ 之父 Bjarne Stroustrup 提出的设计理念,其核心是把资源和对象的生命周期绑定,对象创建获取资源,对象销毁释放资源。在 RAII 的指导下,C++ 把底层的资源管理问题提升到了对象生命周期管理的更高层次。

RAII
struct RAIILog
{
    
    
	 RAIILog()
	 {
    
    
	 	log("start");// 在构造析构函数内指定期望做的操作,可⾃动调⽤
	 }
	 ~RAIILog()
	 {
    
    
	 	log("end");
	 }
}
struct RAIIBuffer;
bool procPanMeasGeo(const cv::Mat& img)
{
    
    
	 RAIILog raii_log;// RAII在函数的花括号内具有⽣命周期,花括号进入⾃动创建,花括号离开⾃动析构
	 log("start");
	 //....
	 if ()
	 {
    
    
		log("end");
		return true;
	 }
	 for ()
	 {
    
    
		 if ()
		 {
    
    
		 	while ()
		 	{
    
    
		 	}
		 	log("end");
		 }
	 }
	 log("end");
	 //随着代码逻辑的增加可能新增return分⽀,但遗忘了做配对的log("end")操作,RAII可⾃动做
	 return true;
}

4.7 函数行数与文件行数

为了易于代码的维护,增加可读性
函数不宜超过150⾏,最好保持在100以内,多了考虑拆分为⼦函数
⼀个文件不宜超过1000行

4.8 函数入参如果不修改需加const

bool procPanMeasGeo(const cv::Mat& img)

4.9 函数内最好是同⼀层次的代码

为了增加可读性和降低逻辑门槛

不建议
bool procPanMeasGFeo()
{
    
    
	findROI();
	fileterROI();
	findEdge();
	// 以下是实现细节,和周围的函数格格不入,容易使得阅读者思路断开
	for (uint32_t i = 0; i < rows; i++)
	{
    
    
		 for (uint32_t i = 0; i < rows; i++)
		 {
    
    
		 //...
		 }
	}
	procMeas();
	return true;
}
建议
bool procPanMeasGFeo()
{
    
    
	findROI();
	fileterROI();
	findEdge();
	findPeak();// 封装
	procMeas();
	return true;
}

猜你喜欢

转载自blog.csdn.net/qq_39839546/article/details/122124658