网站建设开发语言,室内设计效果图用什么软件最好,服装html网站模板下载,校园网站做等级保护规范
C文件名和类名保持一致
好处#xff1a;代码整体结构清晰、明了。java里强制如此。
类型命名采用大驼峰
比如#xff1a;UrlEncoder
FileParser
优先使用 头文件中的基本类型
如#xff1a;
有符号类型 无符号类型 描述 int8_t uint8_t 宽度恰为8的有/无符号整…规范
C文件名和类名保持一致
好处代码整体结构清晰、明了。java里强制如此。
类型命名采用大驼峰
比如UrlEncoder
FileParser
优先使用 头文件中的基本类型
如
有符号类型 无符号类型 描述 int8_t uint8_t 宽度恰为8的有/无符号整数类型 int16_t uint16_t 宽度恰为16的有/无符号整数类型 int32_t uint32_t 宽度恰为32的有/无符号整数类型 int64_t uint64_t 宽度恰为64的有/无符号整数类型 intptr_t uintptr_t 足以保存指针的有/无符号整数类型
尽量不要使用int、long等因为其宽度取决于操作系统和编译器。比如long可能是32bit或64bit。
少用全局变量
使用单例封装性更好。
条件/循环语句必须要使用大括号
在已有条件/循环语句代码上增加新代码时不容易出错
switch语句要有default分支除非switch的条件变量是枚举类型
switch语句中要有default分支保证在遗漏case标签处理时能够有一个缺省的处理行为。
如果switch条件变量是枚举类型加上default分支处理有些多余现代编译器都具备检查是否在switch语句中遗漏了某些枚举值的case分支的能力会有相应的warning提示。 另外加上default分支处理一些静态代码分析工具会报告default分支是死代码deadcode的warning。java也有这种情况。
不允许使用魔鬼数字
缺点没有任何业务含义修改麻烦
//xx
const MAX_VALUE 120; //xx
if (a MAX_VALUE )
if(b MAX_VALUE )
不用的代码段直接删除不要注释掉
现在有git、svn这样的版本管理工具删掉也不怕丢失。
所有头文件都应当使用#define 防止头文件被多重包含
#ifndef VOS_INCLUDE_TIMER_TIMER_H
#define VOS_INCLUDE_TIMER_TIMER_H
...
#endif.h文件用于声明需对外公开的类与接口若没有对外接口.h文件可不要
头文件包含顺序按照稳定度排序
建议按照稳定度排序
cpp对应的头文件C/C标准库系统库的.h其他库的.h本项目内的.h
举例来说Foo.cpp中包含头文件的次序如下:
#include Foo/Foo.h
#include cstdlib
#include string
#include linux/list.h
#include linux/time.h
#include platform/Base.h
#include platform/Framework.h
#include project/public/Log.h不要在头文件中或者#include之前使用using指示符
原因容易造成符号冲突。
在CPP文件的实现代码处可以视情况使用。
类的成员变量必须显式初始化
这跟java是不同的java里类的成员变量会由编译器自动初始化。
若不使用拷贝构造函数或赋值操作符使用private修饰且不实现
class Foo {
private:Foo(const Foo);Foo operator(const Foo);
};C11下也可用delete关键字注意这里的修饰符是public
class Foo {
public:Foo(const Foo) delete;Foo operator(const Foo) delete;
};禁止在构造函数和析构函数中调用虚函数
结果不可知。
比如在基类的构造函数里调用虚函数有可能触发派生类的构造要知道这时候基类还没构造完呢。父之不存子将焉附
同样的道理基类的析构函数调用虚函数这个行为可能下放到派生类但此时派生类已销毁了派生类销毁在基类之前构造则在基类之后。
基类的析构函数应该声明为public和virtual的
原因只有基类析构函数是虚拟的才能保证派生类的析构函数被调用。
输入参数使用引用取代指针尽可能传递const应用
好处引用肯定非空避免繁琐的NULL检查。这是C强于java的地方java里即使引用也可能为null。
把 f(A* a){ … }
改成 f(const A a) {
…
}
少用多重继承
因为多重继承使用过程中有下面的典型问题
菱形继承所带来的数据重复以及名字二义性。因此C引入了virtual继承来解决这类问题;即便不是菱形继承多个父类之间的名字也可能存在冲突从而导致的二义性;如果子类需要扩展或改写多个父类的方法时造成子类的职责不明语义混乱;相对于委托继承是一种白盒复用即子类可以访问父类的protected成员, 这会导致更强的耦合。而多重继承由于耦合了多个父类相对于单根继承这会产生更强的耦合关系。
多使用const来保证数据的不变性
数据不可变多安心啊且并发编程下可以少费脑子去考虑锁的问题。
类型转换
dynamic_castdowncast类似于java的instanceof尽量少用往往是类的继承关系设计的不合理。
reinterpret_cast这个就是强转很危险。
const_cast去掉数据的不可变性不利于代码的稳定和并发操作
智能指针
f(A* a)
A* p new A();
auto_ptr p(new A());
C11普遍推广之前为方便指针管理一般要用auto_ptr。但这玩意也有缺点它有一个隐式的所有权转移行为容易出问题比如不能放容器里、也不建议通过函数参数传递。
使用auto_ptr常见的有两种场景一是作为智能指针传递到产生auto_ptr的函数外部二是使用auto_ptr作为RAII管理类在超出auto_ptr的生命周期时自动释放资源。 对于第1种场景可以使用std::shared_ptr来代替。 对于第2种场景可以 使用C11标准中的std::unique_ptr来代替。其中std::unique_ptr是std::auto_ptr的代替品支持显式的所有权转移。
具体到unique_ptr和shared_ptr优先使用前者。因为
shared_ptr有专门的内存存放引用计数有额外的开销shared_ptr在循环依赖的时候释放不了内存参考python早期的垃圾回收问题
严格的说来unique_ptr是C14的标准晚于shared_ptr。我们只需使用gcc5及以上的版本就没问题。
unique_ptr的使用
unique_ptr可以认为是“禁掉了隐式所有权转移的auto_ptr”实现策略是禁用了拷贝构造和赋值运算符重载。如果需要明确的所有权转移使用std::move。所以有
auto foo std::make_uniqueFoo();
auto foo1 foo; //Cannot compile!
auto foo2 std::move(foo); //its ok, foo has nothing now不推荐复杂的模板编程
比如“模板元编程”当年很痴迷觉得很适合炫技现在觉得太烧脑代码不好维护。
auto
auto用于自动类型推断本质上是一个类型占位符而非真实的类型。可用于替代冗长的类型名比如iterator
注意auto只能替代值类型所以如果传一个引用给auto它会自动去除引用比如下面的例子
class Foo
{
public:Foo() default;Foo(const Foo) delete;Foo operator(const Foo) delete;void doSth(){std::cout do sth std::endl;}
};Foo s;
Foo ref s;
auto s1 ref; //Cannot compile要编译正确需改成
auto s1 ref;override
这个是照抄了Java的override注解用于检查派生类的虚函数定义是否与基类一致重构的时候能起一定的保护作用。
Lambda
Lambda有几个优点
写起来简单可以引用C里叫捕获所在环境的局部变量术语叫闭包不过我更喜欢lua里的叫法upvalue
Lambda在Java里是使用匿名类来实现的upvalue作为匿名类构造器的参数传递进来从而做到长期持有C估计是类似的实现机制。由于java有gc所以不用考虑upvalue生存周期的问题。但C则不然在C里使用Lambda我们引用的upvalue可能只是栈上的对象在lambda执行时已经不存在了这是需要特别注意的。
Lambda的形式
[upvalue] (lambda参数) mutable|exception - 返回值类型 {函数体}upvalue也叫函数对象参数有以下形式
空。没有任何函数对象参数。。函数体内可以使用 Lambda 所在范围内所有可见的局部变量包括 Lambda 所在类的 this并且是值传递方式相当于编译器自动为我们按值传递了所有局部变量。。函数体内可以使用 Lambda 所在范围内所有可见的局部变量包括 Lambda 所在类的 this并且是引用传递方式相当于是编译器自动为我们按引用传递了所有局部变量。this。函数体内可以使用 Lambda 所在类中的成员变量。a。将 a 按值进行传递。按值进行传递时函数体内不能修改传递进来的 a 的拷贝因为默认情况下函数是 const 的要修改传递进来的拷贝可以添加 mutable 修饰符。a。将 a 按引用进行传递。ab。将 a 按值传递b 按引用进行传递。ab。除 a 和 b 按引用进行传递外其他参数都按值进行传递。ab。除 a 和 b 按值进行传递外其他参数都按引用进行传递。
lambda参数有一点不好必须明确给出参数类型做不到自动推断java和scala里都是可以自动推断的。
返回值类型不是必给的编译器可以推断出来。
一个例子
std::vectorstd::string l, r;
l.push_back(e0);
l.push_back(e1);std::transform(l.begin(), l.end(), std::back_inserter(r), [](const std::string v){return v _wrapper;});
std::for_each(r.begin(), r.end(), [](const std::string v){std::cout v std::endl;});