编程札记
今天又在搞粒子编辑器呀,由于开始做之前对粒子编辑模块不够熟悉,设计不合理,后期大改,老板还崔,有些烦燥啊
不过,对于编程中的细节也有了一些小的收获,自己也很是吃惊,原来这么多年来从未真正弄清楚某些特性,哈哈!
一、虚函数
关键字virtual 在基类里边的函数中加上该关键字后,在子类调用父类方法时,父类方法中如果有使用到在子类中被重载的方法,将会调用子类的方法,而不是直接调用父类的方法。
二、关于框架的 搭建
可能需要多了解一些设计模式了吧,总感觉这次很匆忙,很赶,现在就是把东西赶出来而以,来不及思考如果优化框架。我想后边我还是要优化的。因为现在的框架,在写的过程中并不能让我十分清晰的安排好各个功能函数,就好像模块边界不清楚的样子。
三、关于关键字 auto
有时用到跌代器,初始化却需要很长一串代码,显得非常繁锁。在目前C++标准升级之后,使用auto使得跌代器的初始化像声明一个int 一样简单。for循环也变得简洁了。
四、关于对齐
#pragma pack(push) :
编译器编译到此处时将保存对齐状态(保存的是push指令之前的对齐状态)。
#pragma pack(pop):
编译器编译到此处时将恢复push指令前保存的对齐状态(请在使用该预处理命令之前使用#pragma pack(push))。push和pop是一对应该同时出现的名词,只有pop没有push不起作用,只有push没有pop可以保持之前对齐状态(但是这样就没有使用push的必要了)。
#pragma pack():
#pragma pack() 取消自定义对齐方式,恢复默认方式,而push之后pop是回到push指令之前的对齐方式。
这样就可以知道,当我们想要一个结构体按照4字节对齐时,可以使用#pragma pack(4) ,最后又想使用默认对齐方式时,可以使用#pragma pack() 。
关于本条更多:https://www.cnblogs.com/yangguang-it/p/7392726.html
五、关于性能测试
TCMalloc 用于替换系统的内存管理,实现了高效的多线程内存管理
https://www.jianshu.com/p/11082b443ddf
六、关于内存释放
有时引用计数出错时,容易意外释放内存导致致使错误,如:
1.如果基类引擎计数结束,在内部释放了基类,而子类依然存在时,常见的现象是指针看起来正常,但内存计数已出错,且在VS中该指针前边部分看不到内存,仅显示为类名。
七、关于new
可能不曾想过new一个长度为0的数组会怎样,结合网络上的资料以及自身遭遇结果可能是:
类型 *p = new 类型[0];
p为非null指针,但不可对其地址进行操作,否则会异常。
八、关于预编译
碰到一个奇怪的问题:一个头文件中加了锁相关的宏义,并且定义了开关宏,奇怪的是注释掉开关宏仍能找到开关宏定义,各种推测都被证伪之后,发现在头文件对应的源文件中包含该头文件的位置上方,包含了预编译头,并且预编译头中包含了含有定义了该开关宏定义的另一头文件!调换两个头文件的位置之后就找不到锁相关的宏义了!
看来:在源文件中先包含的头文件中定义的宏可以作用到后包含的头文件中。
九、关于显示缓存
https://zhuanlan.zhihu.com/p/33637225(原文链接)
OpenGL和DirectX都支持模板缓冲区,每个像素占的位数通常是1、4、8等。渲染过程中,对片断(Fragment)的处理,包括裁剪测试、透明度测试、模板测试、深度测试等等,它们的顺序如图2所示,模板测试发生在深度测试之间。
十、关内存管理
1.大范围的数据结构需要反复构建和释放的,如果没有有效的机制,靠人力来维护、保证内存的正确使用和释放,由于各种不可控因素,出现问题的概率相当之大。近日就因为一个内存释放问题查了数日毫无结果,只知与声音节点中的内存重重复释放有关,面对庞大的代码结构,面临着详查内存使用情况的窘境。目前数日仅凭堆栈和IDE的输出了推断排查问题,便思索避免产生这种情况的可行措施:
a、使用二级指针使用内存,使用具体变量时,采用封装模版简化变量使用,使用引用计数自动管理内存。
b、制作好相关调试数据、日志线程,方便以内存出问题时与以监管。
十一、关于编程思想
依赖倒置原则(Dependence Inversion Principle,DIP)是指设计代码结构时,高层模块不应该依赖低层模块,二者都应该依赖其抽象。
1.有效控制影响范围
最理想的情况就是,我们已经编写好的代码可以 “万年不变”,这就意味着已经覆盖的单元测试可以不用修改,已经存在的行为可以保证保持不变,这就意味着「稳定」。任何代码上的修改带来的影响都是有未知风险的,不论看上去多么简单。
2.增强代码可读性和可维护性
3.降低耦合
《资本论》中有这样一段描述:
在商品经济的萌芽时期,出现了物物交换。假设你要买一个 iPhone,卖 iPhone 的老板让你拿一头猪跟他换,可是你并没有养猪,你只会编程。所以你找到一位养猪户,说给他做一个养猪的 APP 来换他一头猪,他说换猪可以,但是得用一条金项链来换…
所以这里就出现了一连串的对象依赖,从而造成了严重的耦合灾难。解决这个问题的最好的办法就是,买卖双发都依赖于抽象——也就是货币——来进行交换,这样一来耦合度就大为降低了。
这时候我们再来看代码,无论「我没有三颗心脏」的兴趣怎么暴涨,对于新的课程,都只需要新建一个类,通过参数传递的方式告诉它,而不需要修改底层的代码。实际上这有点像大家熟悉的依赖注入的方式了。
总之,切记:以抽象为基准比以细节为基准搭建起来的架构要稳定得多,因此在拿到需求后,要面相接口编程,先顶层设计再细节地设计代码结构。
十二、关于字符串前加‘R’的作用
在打开文件或正则表达式的时候,在字符串前 加r 和 不加r 是有区别的:
'r'是防止字符转义的, 如果字符串中出现'\n'的话 ,不加r的话,\n就会被转义成换行符,而加了'r'之后'\n'就能保留原有的样子
在字符串赋值的时候 前面加'r'可以保证字符串在输出的时候的时候不被转义,原理是在转义字符前加'\'
如:
十三、关于内存泄漏的问题
接管理编译器的new 和delete,然后分析相应对应内存情况,如
#define DEBUG_NEW new (__FILE__,__LINE__)
#define new DEBUG_NEW
详细方案见原文链接:https://blog.csdn.net/noslopforever/article/details/7973624