C++实战笔记(一)

命名规范:

  • 变量、函数名和命名空间用snake_case,全局变量加"g_"前缀
  • 自定义类名用CamelCase风格,成员函数用snake_case,成员变量加"m_"前缀。
  • 宏和常量应当全大写,单词之间用下划线连接
  • 尽量不要将下划线作为变量的前缀或后缀,很难识别

CamelCase:驼峰命名法,分为大驼峰,小驼峰。区别为首字符是否要大小写。

snake_case:用的全是小写,单词之间用下划线连接。

#define MAX_PATH_LEN 256   //常量全大写
int g_sys_flag;            //全局变量,加"_g"前缀

namespace linux_sys {     //名字空间,全小写
    void get_rlimit_core();   //函数,全小写
}

class FilePath final    //类名,首字母大写
{
public:
    void set_path(const string &str);  //函数,全小写
private:
    string m_path;          //成员变量,加"m_"前缀
    string m_level;
}

 变量/函数的名字长度与它的作用域成正比,局部变量/函数的名字可以短一点,而全局变量/函数的名字应该长一点。

注释规范

// author        : xxx
// date          : 2022-xx-xx
// purpose       : get inner counter value of generic T
// notice        : T must have xxx member
// notice        : return value maybe -1. means xxx, you should
template<typename T>
int get_value(const T& v);

注释用英文,utf8编码。

源码组织和管理

可以不用实现代码分离(.h和.cpp),只用一个文件实现"hpp",可以理解成(.h + .cpp),类的完整实现都写在里面(极少数语法限制必须放在cpp里的成员除外),相当于把原来放在两个文件里的代码整合在一起,大致如下:

#ifndef _XXX_HPP_INCLUDED_
#define _XXX_HPP_INCLUDED_
class XXX final
{
public:
    void function1() {...}
    void function2() {...}
};

#endif  //_XXX_HPP_INCLUDED_

好处:方便源码管理

代码风格其它注意事项

  • 代码行宽尽量限制在80列之内,超过了必须换行缩进对齐
  • 花括号"{}"应该保持一致的对齐格式,“{”单独一行或者在行尾都可以,但"}"必须单独一行且后面留以空行
  • if-else/for等复合语句,即使只有一行也使用花括号。 
  • if-else/switch/for等语句的嵌套层不宜过深,否则不仅阅读困难,还增加了逻辑复杂
  • 循环语句、函数体不宜过长,尽量控制在50-100行,这样可以在一个页面内显示完整
  • 函数的入口不宜过多,如果确实有必须应用struct/tuple打包

包含文件

常用的预处理指令应该是"#include",它的作用是"包含文件"。注意,它不是“包含头文件”,而是包含任意文件。 “#include”其实是非常"弱"的,不做什么检查,就是“死脑筋”地把数据合并进源文件。

所以我们在写头文件的时候,为了防止代码被重复包含,通常加上“Include Guard”,也就是用"#ifndef/#define/#endif"来保护整个头文件,如下:

#ifndef _XXX_H_INCLUDE_   //检查是否定义了宏
#define _XXX_H_INCLUDE_   //没有则定义宏
...                       //头文件内容
#endif                    //_XXX_H_INCLUDE

通常C++预处理器还支持使用"#pragma once"防止重复包含,但存在兼容问题。

 宏定义

“#define”是预处理编程里的核心指令,它用来定义源码级别的“文本替换”,也就是我们常说的“宏定义”。

  1. 宏的展开、替换发生在预处理阶段,所以对于一些调用频繁的小代码片段来说,用宏来封装的效果比使用inline关键字要好,因为它实现了源码级的无条件内联。
#define ngx_tolower(c) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c)
#define ngx_toupper(c) ((c >= 'a' && c <= 'z') ? (c &~ 0x20) : c)

#define ngx_memzero(buf, n)    (void) memset(buf, 0, n)

     2.宏没有作用域概念,永远全局生效。对于临时的宏,最好用完后尽快使用#undef取消定义,避免发生冲突

#define CLUB(a) (a) * (a) * (a) //定义求立方的宏
cout << CLUB(10) << endl;
cout << CLUB(15) << endl;
#undef CLUB   //取消定义

或者


#ifdef AUTH_PWD
#  undef AUTH_PWD
#endif
#define AUTH_PWD "xxx"

    3. 消除魔鬼数字

#define MAX_BUF_LEN  65535
#define VERSION  "10.0.18"

  4. 文本替换

#define BEGIN_NAMESPACE(x)   namespace x{
#define END_NAMESPACE(x)     }

//使用
BEGIN_NAMESPACE(my_own)
...  //functions and classes
END_NAMESPACE(my_own) 

条件编译

#ifdef __cplusplus //标记C++版本号
    extern "C"{
#endif
    void a_c_function(int a);
#ifdef __cplusplus
    }
#endif
#if __cplusplus >= 202002   //检查C++版本号
    cout << "c++20 or later" << endl;
#elif __cplusplus >= 201703
    cout << "c++17 or later" << endl;
#else   // __cplusplus < 201703
#   error "C++ is too old"
#endif

C++里面定义的预定义的宏,可以帮助我们识别编译环境,具体内容如下:

__FILE__:源文件名
__LINE__:源文件行号
__DATE__:预处理时的日期
__has_include:是否存在某个可包含的文件
__cpp_modules:是否支持模块机制
__cpp_decltype:是否支持decltype特性
__cpp_decltype_auto:是否支持decltype(auto)特性
__cpp_lib_make_unique:是否提供函数make_unique()

属性

属性没有新增关键字,而是用两对方括号的形式标识,即"[[...]]",方括号的中间填写的是属性标签。

下面是一个简单的例子,显示声明函数没有返回值,一看就能明白:

[[noreturn]]          //属性:函数绝不会返回任何值
int func(bool flag)
{
    throw std::runtime_error("XXX");  //只抛出异常
}

目前认为比较有用的属性:

noreturn : 显式声明函数无返回值
nodiscard : 显式声明不允许忽略函数返回值
deprecated : 废弃某段代码,不鼓励使用
maybe_unused : 显示标记某段代码暂时不用,但保留,因为将来可能要用
fallthrough : 仅用于switch语句中
likely/unlikely : 标记某段代码路径更可能/更不可能执行,指示编译器优化

静态断言

assert是一个宏,它在预处理阶段并不生效,而是在运行阶段才起作用,所以assert又叫做“动态断言”。

static_assert是一个专门C++关键字而不是宏,因为它只在编译时生效,运行阶段“看不见”,所以是静态的。它是在编译阶段检测各种条件的断言,表达式值如果是false就会报错,导致编译失败。

可以配合标准库里的“type_traits”,它提供了对应这些概念的各种编译期“函数”,又叫“模板元函数”:

static_assert(is_integral_v<T>); //断言T是整数类型
static_assert(is_pointer_v<T>); //断言T是指针类型
static_assert(is_default_constructible_v<T>); //断言T有默认构造函数

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值