C++编程原则2 tcy
8)函数编写原则
9)避免代码重复
10)复制后交换
11)不要在使用C语言的风格
12)删除-擦除技术
13)if...else优化技术参考本人博文
14)少用循环
1.函数编写原则
1.1.基本原则:1)只做一件事情;让函数尽可能小12-15行2)尽量使用内联函数;一般可以忽略函数的调用开销3)通过引用传递结构体而不是传值;小心使用表查找函数;对GPU编程优先使用表查找
1.2.函数命名通常是动词状态函数is...,has...;使用容易理解名字
1.3.函数参数1)减少函数参数个数,应小于3个,类中可无参数旧函数参数太多重新包装;用struct合并一些参数2)避免使用标志参数void foo(){ if(readMode) {} else {}}//应分成2个单独良好命名的函数3)尽可能使用const防止传递给函数的参数被修改const long double PI=3.1415926;int foo(Car const*car); //静态指针变量-指针指向内容不能被修改 等价const Char* carvoid foo(Car* const car); //指针常量,可修改car,但不能修改指针int foo(Car const* const car); //都不能修改void view(const string& message); //静态字符串引用,不许修改strvoid view(string const& message); //等同上面 注:const都会修饰他左边的内容,如左边没内容就修饰右边
1.4.函数返回值1)避免使用输出参数-不惜一切代价也要避免使用输出参数2)多输出使用std::pair,std::tuple(仅在特殊情况使用)通常用struct类如果你还必须区分成功失败,可用所谓的特例模式实例:多个输出值using pairType = pair<int, string>;using tupleType = tuple<int, string, string>;struct resultType{int i;string s;}; pairType foo(){ return pair<int, string> { 1,"Tom" }; }tupleType bar() { return make_tuple( 2, "Tom", "Bob"); }//tupleType{}resultType func() { return resultType{ 3,"Jim" }; } int main() {int i; string s; pairType p=foo();std::tie(i, s) = p;assert(i==p.first);assert(s==p.second);tupleType t = bar();std::tie(i, s, ignore) = t;assert(i==std::get<0>(t));assert(s==std::get<1>(t));resultType r = func();cout<<r.i<<r.s<<endl; }
1.5.指针参数或返回值
1)说明:a)不要传递或返回nullptr,把要做什么转移给调用者会出现很多选择语句b)如函数返回常规指针确保指针始终指向有效地址,为nullptr则抛出异常. 2)避免指针策略:a)首选在栈上而不是在堆上构造对象;move摆脱大量常规指针int foo(){int tmp=1;return tmp;} //在栈上vector<int> foo(){vector<int> vec{2};return vec;}//原因所谓move,所有容器都支持 b)在函数参数用const引用代替指针void func(Type* p);void func(const Type& p); c)如不可避免使用处理指向资源的指针请用智能指针如必须在堆上分配资源应利用RAII(资源申请即初始化)意味这你使用智能指针 d)第三方库API返回原始指针有依赖问题,通常不在我们的控制范围可创建自定义智能指针来包装常规指针,由API的allocator分配,deallocator需重新包装
3)实例:访问windows资源#include<windows.h>typedef void *HANDLE;const DWORD processId= 4711;HANDLE processHandle=OpenProcess(PROCESS_ALL_ACCESS,FALSE,processId);//检索进程句柄BOOL success=CloseHandle(processHandle);//关闭句柄< /FONT>//包装:自定义删除器deleterclass Win32HandleCloser{public:void operator()(HANDLE handle)const{ if(handle!=INVALID_HANDLE_VALUE) CloseHandle(handle);}}; using Win32SharedHandle=std::shared_ptr<HANDLE>;const DWORD processId= 4711;Win32SharedHanle processHandle{OpenProcess(PROCESS_ALL_ACCESS,FALSE,processId),Win32HandleClosedr());
2.避免代码重复
1.1.说明:避免代码重复,传统做法用const版本实现非const版本建议使用变为const又变回来技术来避免代码重复。 1.2.一般来说使用下面的模式:returnType Class::func(arguments){ return const_cast<returnType>(std::as_const(*this).func(arguments ));}//return const_cast<T&>(static_cast<const Array<T>&>(*this)[index]); 2.实例:template <typename T>T& Array<T>::operator[](size_t index){Array<T>& nonConstRef=*this;const Array<T>& constRef=as_const(nonConstRef);//转变为const引用const T& constResult= constRef[index]; //获取const结果 return const_cast<T&>(constResult); //转换到非const结果}
3.复制后交换
1.1.定义:任何函数都可抛出异常(除noexcept标注函数,析构函数)操作要么全部成功要么全部失败,可使用的编程模式称为复制后交换1.2.用途:如在修改中出现异常丢弃副本原对象不变;任何代码都可运用,但常用在成员函数中1.3.步骤:如修改一个或多个对象状态,任何步骤都可抛异常,应采用下面简单模式:1)创建对象的一个副本2)修改对象的副本而不是原对象3)如果修改成功则用副本替换或交换原对象1.4.说明:1)复制后交换依赖如下假设:最后的交换步骤没有抛出异常的风险2)swap()用来交换任何可复制数据类型的值或对象<utility>类似template<typename T> void swap(T& one,T& other)noexcept{ T copy(one); one=other; other= copy;}
2.实例:
实例1:template<typename T>class Array{};template<typename T> //版本1Array<T>& Array<T>::operator=(const Array& rhs){if(this!= &rhs){Array<T> copy(rhs};swap(copy);}return *this;}template<typename T> //版本2:不在需要检查自我赋值Array<T>& Array<T>::operator=(const Array& rhs){swap(rhs);return *this;}在Array<>对象应用这个模板函数效率不高,被交换对象的所有元素会被复制多次,而且在我们的赋值运算符中不能用他来交换*this 和copy.(会调用赋值运算符出现无限递归调用)
实例2:添加swap成员函数:应实现一特化版本,因为Array<>成员变量是私有,一个选项将swap()定义为友元函数方法2向Array<>添加一个额外的成员函数swap()(也是vecor<>采用方法) template<typename T>void Array<T>::swap(Array& other) noexcept{std::swap(elements,other.elements);//交换两个指针std::swap(size,other.size);}//然后使用该成员函数版本实现传统的非成员函数swap()template<typename T>void swap(Array<T>&one,Array<T>& other) noexcept{ one.swap(other);} //转发到公共成员功能
4.不要在使用C语言的风格
1.避免使用宏1)常量定义constexpr double pi=3.1415926;函数宏用函数替代;2)主要用在特殊目的如单元测试或日志框架
2.用C++类型转换代替C风格强制转换
2.1.说明:1)修改设计避免在任何情况下进行类型转换;2)如无法避免用static_cast,用远不要使用C风格转换3)不要使用dynamic_cast<>这是一个糟糕的设计4)在任何情况下永远不要使用reinterpret_cast<>.转换不安全不可移植和依赖于实现等标标志2.2.实例:double d{3.14};int i= (int)d;int i= static_cast<int>(d);
3.字符串
3.1.用string和stream替代char*char name[]= "Tom"; //用下面替换string name{"Tom"}; //string name("Tom"); //字符数组通常在传递其首元素的指针才能使用char *p= name;void func(char* pointerToCharacterArray); //唯一使用C风格的字符串是字符串常量:const char* const address="shanghai";
3.2.避免用printf,sprintf,gets数字类型都可to_string()转换为字符串转换唯一的缺点是有时是不准确的double d{1e-9};改进:#include<string>#include<sstream>#include<iomanip> string doubleToString(const long double x,const int precision){stringstream stream{};stream<<std::fixed<<std::setprecision(precision)<<x;return stream.str();}
4.数组
4.1.固定数组用标准库std::array<Type,N>替代int arr[]={1,2,3};void foo(int *arr,size_t n){} #include<array>array<int,3> arr{1,2,3};void foo(const array<int,3>& arr){size_t n=arr.size();}
4.2.可变数组用std::vector替换1)遵守以下规则(1)fun()不应访问超出数组范围的元素(2)向量中元素必须是连续的2)说明:你用&vi[0]和&*v.front()作为其内部数组地址就会很安全3)实例: void func(const int arr[], size_t length ){}int main(){vector <int> vec;func(&vec[0], vec.size());//或者&*v.front()}
4.3.动态多维数组和向量//手动分配多维数组,非常容易出错int (*pArr)[5] = new int[2][3]; //需要括号pArr[0][0] = 10;pArr[0][1] = 11;pArr[0][2] = 12;pArr[1][0] = 20;pArr[1][1] = 21;pArr[1][2] = 22;for (auto i = 0; i < 2; ++i){for (auto j = 0; j < 3; ++j)cout << pArr[i][j] << ",";cout << endl;}delete [] pArr;
//使用vector来模拟多维数组是一个更好的选择:#include <vector>#include <iostream>using namespace std; int main(){vector <vector <int> > v;v.push_back(vector <int>());v.push_back(vector <int>());v[0].push_back(10);v[0].push_back(11);v[0].push_back(12);v[1].push_back(20);v[1].push_back(21);v[1].push_back(22);for (auto v1 : v){for (auto v2 : v1)cout << v2 << ",";cout << endl;}}
5.替换C语言中指针int* add(int* p1,int* p2){static int result = *p1 + *p2;return &result;}
using intPtrType = shared_ptr<int>; intPtrType add(intPtrType p1, intPtrType p2){ return std::make_shared<int>(*p1 + *p2);} int main() {//普通指针测试:int x = 1, y = 2;int *px = &x, *py = &y;cout << *add(px, py) << endl;//smart指针测试:intPtrType p1 = make_shared<int>(x);intPtrType p2 = make_shared<int>(y);intPtrType r = add(p1, p2);cout << *r << endl; }
删除-擦除技术
1.1.提示:不应手动迭代顺序容器的元素,而是用删除-擦除技术使用remove(),或remove_if()算法来删除容器中满足特定条件的元素1.2.remove(),或remove_if()返回迭代器指向要删除的第一个元素不会真正删除元素,会将不应该删除的元素移到输入范围的前部,需要删除的元素移到后部
2.实例:
实例1:普通迭代删除:效率低void removeEvenNumbers(NumberContainer& vec){for (auto iter{ vec.begin() }; iter != vec.end(); ){iter = (*iter % 2 == 0) ? vec.erase(iter) : (iter + 1);}}
实例2:删除-擦除技术#include <vector>#include <string_view>#include <iostream>#include <algorithm>using namespace std;std::vector<int> fillVector(size_t N); // Fill a vector with 1, 2, ..., Nvoid print(std::string_view message, const std::vector<int>& vec);void removeEvenNumbers(std::vector<int>& vec);int main(){const size_t n{ 6 };auto vec{ fillVector(n) };print("The original set of vec", vec);removeEvenNumbers(vec);print("The vec that were kept", vec);}std::vector<int> fillVector(size_t N) // Fill a vector with 1, 2, ..., N{std::vector<int> vec;for (int i{ 1 }; i <= N; ++i)vec.push_back(i);return vec;}void print(std::string_view message, const std::vector<int>& vec){std::cout << message << ": ";for (int number : vec) std::cout << number << ' ';std::cout << std::endl;}void removeEvenNumbers(std::vector<int>& vec){// remove all even vecauto vector_iter{ std::remove_if(begin(vec),end(vec), [](int number) { return number % 2 == 0; }) };cout << typeid(vector_iter).name() << endl;//std::_Vector_iterator// Erase all elements including and beyond vector_itervec.erase(vector_iter, end(vec)); //erase缺少第二个参数将仅仅删除一个元素}
C++编程原则2 tcy相关推荐
- C++编程原则1 tcy
1.1.基本原则1)保持简单和直接原则KISS( keep it simple ,stupid)2)不要原则YAGNI(You aren' gonna need it.)确定真的必要时在写代码:以后也 ...
- 每个程序员都必须遵守的编程原则
好的编程原则跟好的系统设计原则和技术实施原则有着密切的联系.下面的这些编程原则在过去的这些年里让我成为了一名优秀的程序员,我相信,这些原则对任何一个开发人员来说,都能让他的编程能力大幅度的提高,能让他 ...
- 程序员应该遵守的编程原则
为什么80%的码农都做不了架构师?>>> 好的编程原则跟好的系统设计原则和技术实施原则有着密切的联系.下面的这些编程原则在过去的这些年里让我成为了一名优秀的程序员,我相信,这些 ...
- [温故知新] 编程原则和模式
写了这么多年代码,依旧做不好一个项目 做好一个项目是人力.产品.业务.技术.运营的结合,可能还叠加一点时机的因素,就我们码农而言,工作就是搬砖,实现产品, 给业务提供支撑. "给祖传代码加 ...
- 推荐给程序员们的十条编程原则
对于新手程序员们来说,拥有良好的代码量积累和一定的熟练度可以顺利的上手工作:而想要进一步的提升自己的代码能力和工作效率,掌握必要的编程原则也是重要的环节. 前言 对于新手程序员们来说,拥有良好的代码量 ...
- 大牛架构师珍藏的10条编程原则
程序员拥有一个较好的编程原则能使他的编程能力有大幅的提升,可以使其开发出维护性高.缺陷更少的代码.以下内容梳理自StactOverflow的一个问题:编程时你最先考虑的准则是什么? 目录 KISS(K ...
- 超级干货:你应该知道的那些编程原则!!
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | Mouse 来源 | http://r6d.c ...
- 程序员能力提升:你应该知道的那些编程原则!!
本文翻译自Programming Principles(http://java-design-patterns.com/principles/). 每个程序员都可以从理解编程原理和模式中受益.这篇概述 ...
- 面向对象编程原则(06)——依赖倒转原则
版权声明 本文原创作者:谷哥的小弟 作者博客地址:http://blog.csdn.net/lfdfhl 参考资料 <大话设计模式> 作者:程杰 <Java设计模式> 作者:刘 ...
最新文章
- mongodb系列~mongodb慢语句(2)
- 项目添加JWT工具类
- C#语法精髓之常用的操作符
- 删除隐藏版本信息 版本回退_Qt如何给程序添加版本信息
- 热启动必须联网吗_供暖结束,地暖是关闭供水阀门还是关闭回水阀门?你做对了吗?...
- centos7配置jdk1.8环境变量
- 作者:谢华美(1976-),男,中国人民银行征信中心数据部副总经理
- mysql如何大矩阵_如何打印矩阵
- 高考数据分析和读书感悟
- AngularJs学习的前景及优势
- 干货 | 大公司机器学习算法的面试经验
- cvs数据格式 gps_CSV、TXT 和 GPX 文件
- 诺德舞台电钢琴采样-Nord Stage 3 Ultimate Stage Pianos
- mosquitto无法连接
- 硬盘格式化数据恢复的软件推荐
- 感谢爱测未来,零基础的我的实习期是这么过来的
- 多模态机器学习概述及其音视频融合总结
- java计算上个工作日方法
- iOS UIButton文字与图片交换位置
- Linux解压rar压缩文件的详细方法
热门文章
- Python 爬虫的工具列表( 附Github代码下载链接)
- 看涨期权(call options)
- 养殖场环境监控系统解决方案
- Windows Server 8 beta 简体中文版 64位 官方原版
- Discuz X3.0,X2.5最新帖子单页展示教程,附懒人包,站长基地zzjidi.com
- 物理像素,逻辑像素(pt),css像素(px),像素比(dpr)都是什么?px,em,rem等 都是什么?有什么区别?
- 智能补货 (在途、现有库存、安全库存) 的思路
- rabbitmq连接认证_RabbitMQ配置使用SSL加密通信
- @Consumes @Produces的作用
- 巴媒:帕托新合同年薪190万欧,相比天海时期大幅缩水_虎扑中国足球新闻