C++编程规范和问题整理

C++编程规范

文件命名

接口类单独头文件,实体类单独头文件,实现单独cpp文件
好处:客户程序只需要包含接口类头文件,实体类与实现只与实现细节有关。

函数

函数有多个退出点是不好的设计

类中委托指针,只能指向抽象类。

输入参数检查,凡是,有外部输入的参数都需要检查。

class

成员变量以m_开头
成员函数用小写单词之间用_隔开
类的大括号跟函数一样,类名后重启一行。
类中的内容两个空格开头

代码风格

注释

英文语法问题

C++ 规范

使用最新的编程规范

C++ const使用

const 用来使用变量的形式定义枚举和宏
const 定义的变量内容不能改变,const变量的值在声明的赋给初值,后边不能改动。使用中const变量只能作为右值(rvalue)。在修饰形参引用变量时,表示引用所表示的变量是constant,在传参时,初始化了一个const 引用。若形参不是const,输入参数则必须是左值,输入参数的值能够被改变。
const 对象只能调用const 成员函数。
成员函数后加const 表示该成员函数不会改变成员变量。

C++ 初始化和赋值的区别

变量的初始化(initialization)和赋值(assignment)是两个不同的概念。
变量初始化有3种方式:

int var = 8; 
int var(8);
int var{8};

第一种方式是一种初始化语法,=并不是赋值操作。
它不同于以下的赋值操作。

int var;
var= 8;

对于基本数据类型来说,这两种写法能生成相同的执行码,但是对于class 变量来说,是完全不同的。
如下代码:

#include <iostream>

class init_assignment
{
public:
  init_assignment() {
    var_name = "default";
    std::cout << "init_assignment()" << std::endl;
    std::cout << "var:" << var_name << std::endl;
  }
  init_assignment(const std::string &v) {
    var_name = v;
    std::cout << "init_assignment(const std::string &v)" << std::endl;
    std::cout << "var:" << var_name << std::endl;
  }
  init_assignment(const init_assignment &input) {
    var_name = input.get_var_name();
    std::cout << "init_assignment(const init_assignment &input)" << std::endl;
    std::cout << "var:" << var_name << std::endl;
  }
  const init_assignment &operator=(const init_assignment &input)
  {
    std::cout << "init_assignment &operator=(const init_assignment &input)"
    << std::endl;
    std::cout << "before assignment var:" << var_name << std::endl;
    var_name = input.get_var_name();
    std::cout << "after assignment var:" << var_name << std::endl;
    return *this;
  }
  ~init_assignment(){
    std::cout << "~init_assignment()" << std::endl;
    std::cout << "var:" << var_name << std::endl;
  }

  const std::string &get_var_name(void) const {
    return var_name;
  }
private:
  std::string var_name;
};

int main(int argc, char *argv[])
{
  init_assignment test1("hello");
  init_assignment test2 = init_assignment("help");
  init_assignment test3;
  test3 = init_assignment("rock");
}

运行结果:

~/pro/c_pp/test$ ./test
init_assignment(const std::string &v)
var:hello
init_assignment(const std::string &v)
var:help
init_assignment()
var:default
init_assignment(const std::string &v)
var:rock
init_assignment &operator=(const init_assignment &input)
before assignment var:default
after assignment var:rock
~init_assignment()
var:rock
~init_assignment()
var:rock
~init_assignment()
var:help
~init_assignment()
var:hello

可以看到在test2初始化时只调用了一次构造函数init_assignment(const std::string &v) 并没有赋值操作,所以初始化时的= 不是赋值操作符。
在进行赋值操作时,test3 = init_assignment(“rock”) 会首先构造rock, rock是一个没有名字的临时变量。调用了赋值操作符重载函数进行操作。从析构的过程中可以看到rock被析构了两次,对应的是临时变量和test3. help 被析构了一次,对应的是test2.

动态分配数组的方法

很多时候会出现下面的场景,函数传递一个size参数,在函数中需要动态分配一个临时数组,并且这个数组需要初始化为0。

不合适方式1

void func(uint8_t *buffer, int size)
{
uint8_t recv_data[size];
memset(recv_data, 0, size);
}

这种方式存在明显的问题,当输入size出现异常巨大的值时,会stack overflow。

不合适方式2

void func(uint8_t *buffer, int size)
{
recv_data = new uint8_t[](size);

}

在heap上分配内存,这时必须检测是否分配成功。这种方式比方式一略微合理,检查多一点工作量。

推荐方式

仍然在heap中分配内存,但是将检查动作交给STL库完成。因为STL库的分配器对内存分配失败有更加细致的处理方式。


void func(uint8_t *buffer, int size)
{
std::vector<uint8_t> data_vector(size, 0);
uint8_t *recv_data = data_vector.data();

}

头文件自满足

头文件内使用到的类型必须有相应的头文件在这个头文件里边。

static 函数

static 函数可以调用本函数域内的私有成员

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值