外观
11.智能指针分析、逻辑操作符的陷阱、逗号操作符的分析、前置操作符和后置操作符
约 1683 字大约 6 分钟
C++智能指针逻辑操作符逗号操作符
2022-06-16
三十七、智能指针分析
1、永恒的话题
- 内存泄漏(臭名昭著的Bug)
- 动态申请堆空间,用完后不归还
- C++语言中没有垃圾回收的机制(java/c# 有)
- 指针无法控制所指堆空间的生命周期
2、编程实验:内存泄漏

3、深度的思考
- 我们需要什么
- 需要一个特殊的指针
- 指针生命周期结束时主动释放堆空间
- 一片堆空间最多只能由一个指针标识(防止释放时,多次释放同一个地址的的内存)
- 杜绝指针运算和指针比较
4、解决方案
- 重载指针特征操作符( -> 和 *)
- 只能通过类的成员函数重载
- 重载函数不能使用参数
- 只能定义一个重载函数
5、编程实验:智能指针


6、智能指针分析
智能指针的使用军规:只能用来指向堆空间中的对象或者变量
7、小结
- 指针特征操作符( -> 和* )可以被重载
- 重载指针特征符能够使用对象代替指针
- 智能指针只能用于指向堆空间中的内存
- 智能指针的意义在于最大程度的避免内存问题
三十八、逻辑操作符的陷阱
1、潜规则
- 逻辑运算符的原生语义
- 操作数只有两种值( true 和 false )
- 逻辑表达式不用完全计算就能确定最终值(短路法则)
- 最终结果只能是true 或者false
2、编程实验:逻辑表达式

3、重载逻辑操作符
逻辑操作符可以重载吗?重载逻辑操作符有什么意义?
4、编程实验:重载逻辑操作符

5、问题的本质分析
- C++通过函数调用扩展操作符的功能
- 进入函数体前必须完成所有参数的计算
- 函数参数的计算次序是不定的
- 短路法则完全失效
6、重载逻辑操作符
- 逻辑操作符重载后无法完全实现原生的语义
- 一些有用的建议
- 实际工程开发中避免重载逻辑操作符
- 通过重载比较操作符代替逻辑操作符重载
- 直接使用成员函数代替逻辑操作符重载
- 使用全局函数对逻辑操作符进行重载
7、小结
- C++从语法上支持逻辑操作符重载
- 重载后的逻辑操作符不满足短路法则
- 工程开发中不要重载逻辑操作符
- 通过重载比较操作符替换逻辑操作符重载
- 通过专用成员函数替换逻辑操作符重载
三十九、逗号操作符的分析
1、逗号操作符
- 逗号操作符( , )可以构成逗号表达式
- 逗号表达式用于将多个子表达式连接为一个表达式
- 逗号表达式的值为最后一个子表达式的值
- 逗号表达式中的前N-1个子表达式可以没有返回值
- 逗号表达式按照从左向右的顺序计算每个子表达式的值

2、实例分析:逗号表达式的示例

3、重载逗号操作符
- 在C++中重载逗号操作符是合法的
- 使用全局函数对逗号操作符进行重载
- 重载函数的参数必须有一个是类类型
- 重载函数的返回值类型必须是引用??????

4、编程实验:重载逗号操作符

5、问题的本质分析
- C++通过函数调用扩展操作符的功能
- 进入函数体前必须完成所有参数的计算
- 函数参数的计算次序是不定的
- 重载后无法严格从左向右计算表达式
6、工程中不要重载逗号操作符!
7、小结
- 逗号表达式从左向右顺序计算每个子表达式的值
- 逗号表达式的值为最后一个子表达式的值
- 操作符重载无法完全实现逗号操作符的原生意义
- 工程开发中不要重载逗号操作符
四十、前置操作符和后置操作符
1、值得思考的问题
下面的代码有没有区别?为什么?

两行语句独立,这个时候没有使用返回值,所以编译期自动优化为一致的。
2、编程实验:真的有区别吗?
3、意想不到的事实
两行语句独立,这个时候没有使用返回值
- 现代编译器产品会对代码进行优化
- 优化使得最终的二进制程序更加高效
- 优化后的二进制程序丢失了C/C++的原生语义
- 不可能从编译后的二进制程序还原C/C++程序
4、思考:++操作符可以重载吗?如何区分前置++和后置++?
5、++操作符重载
- ++操作符可以被重载
- 全局函数和成员函数均可进行重载
- 重载前置++操作符不需要额外的参数
- 重载后置++操作符需要一个int类型的占位参数
6、编程实验:++操作符的重载

7、真正的区别
对于基础类型的变量
- 前置++的效率与后置++的效率基本相同(汇编二进制代码一样)
- 根据项目组编码规范进行选择
对于类类型的对象
- 前置++的效率高于后置++
- 尽量使用前置++操作符提高程序效率
8、编程实验:复数类的进一步完善


9、小结
- 编译优化使得最终的可执行程序更加高效
- 前置++操作符和后置++操作符都可以被重载
- + +操作符的重载必须符合其原生语义
- 对于基础类型,前置++与后置++的效率几乎相同
- 对于类类型,前置++的效率高于后置++
