美文网首页
第1/2章: C++ 建议 / 两种不变性 const & co

第1/2章: C++ 建议 / 两种不变性 const & co

作者: my_passion | 来源:发表于2022-06-20 23:05 被阅读0次

    第1章 C++ 设计原则 / 对 C & C++ 程序员的建议

    1.1 C++ 设计 2 个原则

    (1) 不给比 C++ 更底层的语言 留任何余地
    
    (2) 零开销原则/ZOP
        与等价的 替代方法相比, 不浪费 1个字节(空间) 或 1个CPU时钟周期(时间)
    

    1.2 建议

    1 对 C++ 程序员的建议

        用 C++11 新特性, 使之 更现代化
        
        (1) 
            用    ctor       建立 不变式
        
            配合 ctor/dtor  简化 资源管理(RAII)
        
        (2) 优先用...      而非...
            ——————————————————————————————————————————————————————
            容器和算法       内置数组 和 专用代码
            ——————————————————————————————————————————————————————
            标准库         自己开发的代码
            ——————————————————————————————————————————————————————
            异常          错误代码 来报告 不能局部处理的错误
            ——————————————————————————————————————————————————————
    
        (3) smart ptr 
        
            ————————————————————————————————————————————————————————————————
            避免裸的 new/delete
            ————————————————————————————————————————————————————————————————
            用 unique_ptr 引用 多态对象
            ————————————————————————————————————————————————————————————————
            用 shared_ptr 引用 共享对象, 即 不止1个 owner 负责其析构 的对象
            ————————————————————————————————————————————————————————————————
        
        (4) 用 移动语义 来避免 copy 大对象
        
        (5) 用 模板 来保持 静态类型安全(消除 类型转换), 并 避免 类层次的 不必要使用
    

    2 对 C 程序员的建议

        (1) 想发挥 C++ 相对于 C 的优势, 要采用 `(与 C) 不同的 设计&实现 风格`
            
            学 C++ 标准库 -> 与 C标准库 diff
            
                字符串 copy/cmp 用 =/== 而不是 strcpy()/strcmp() 等
            
        (2) 宏: C++ 几乎从来不用 -> 替代
        
            1) 定义 explicit 常
                const / constexpr / enum (class)
                
            2) 避免 函数调用开销
                inline
            
            3)  指明 函数族/类型族
                template
                
            4) 避免 名字冲突
                namespace
                
        (3) 优选...           而不是...                  
            new/vector      malloc()/realloc()
            std::vector     数组  
            std::string     C 风格字符串
            
        (4) 
            避免用 void* / union / 类型转换, 除非在 某些函数或类的 深层次实现中
            否则
                1) 会限制你从 类型系统 得到的 支持
                2) 通常, 1次 类型转换 就暗示着 1个 设计错误
            
            若 必须用 显式类型转换, 优选 命名的 显式类型转换(static_cast 等), 更准确地 表达意图
            
        (5) 真正需要 变量时, 再声明 并 立即初始化
    
        (6) 不要认为 用 C 风格辛苦写出的程序会 比 简短的C++替代程序(如使用 标准库) 更高效
            实际上, 通常正好相反
    

    第2章 C++ 概览: 基础知识

    2.1 基本概念

    1 类型 / 初始化

        (2) 初始化方式
            1) 列表 {} 
                1) = 可选
                2) 确保不会发生 窄化类型转换
            
            2) = 
                = 配合 auto
                    不存在 可能发生错误的 类型转换
                
                何时该用 auto?
                    无明显理由 需 显式指定类型
    

    2 2种 不变性 / 常量 / 常量表达式 / constexpr 函数

        (1) 3个难点
            1) 
                常量    : 初始化(编译时/运行时) 之后, 值不会再改变
                常量表达式: 编译时能求值
            
            2)
                const     常量: 可在 `运行时求值`
                      /|  |
                  必为 |  | 未必为
                       |  |/
                cosntexpr 常量: `编译时能求值`
            
            3) cosntexpr 函数 
                实参 为 常量表达式  : 编译时求值 => 结果 (是常量表达式) 可用于 常量表达式 
                实参 为 非常量表达式: 运行时求值 => 结果不可用于常量表达式
            
        (2) C++ 支持 `2种 不变性`
        
            ——————————————————————————————————————————————————————————————————————————————
                    |       const                | constexpr
            ——————————————————————————————————————————————————————————————————————————————  
                    |                            | 1) 对象定义
            含义  | (编译器)承诺不改变这个值      |      编译时求值(若求不出 => 报错)
                    |                            | 2) 函数定义
                    |                            |   若 实参 为 常量表达式/else, 
                    |                            |   则 函数 应该能/不能 用在 常量表达式
            ——————————————————————————————————————————————————————————————————————————————  
                    |   说明`接口`               | 
            主要用于|                            | 1) 数据 放 只读内存 / 提升性能
                    |                            | 2) ...
            ——————————————————————————————————————————————————————————————————————————————
            
                                 constexpr double res1 = square(v1);    
                               /    
                              / 1) 若 square(10) 是 常量表达式, 则 正确
            // 常量                           
            cosnt int v1 = 10;  
                              \ 2) 与 用 constexpr 含义等价 
                               \
                                 const double res2= square(v1); 
            
                                 constexpr double res3 = square(v2);    
                              /  
                             /    
                            / 3) error!!! : var2 不是 常量表达式   
            // 非常量     /                
            int v2 = 10;        
                           \    
                            \ 4) ok: 运行时 求值
                             \
                                cosnt double res4 = square(v2); 
            
            5) double sum(const vector<double>&); // sum 不更改 其 参数的值
        
        (3) 常量表达式 应用
            1) 语言规则需要
                1> 数组 size
                2> case 标签
                3> constexpr 声明的 常量
                4> (某些) 模板实参
                        
            2) 不变性 (对象状态 不发生改变) 
            3) 编译时求值:性能高    
    
        new 运算符 分配内存的区域
            自由存储 / 动态内存 / 堆: 3 者含义相同            
    

    2.3 模块化

    模块
        函数 / 用户自定义类型 / 类层次 / 模板
        
    构建C++ 程序的关键
        模块间: 清晰定义交互关系
            
        某模块:接口与实现 分离
    
    模块化
        逻辑上
            通过 语言特性 描述模块
            
        物理上
            通过 划分文件 和 分离编译 分离/组合模块              
    

    1 分离编译

        (1) 含义
            user 代码只能看见所用 类型和函数 的 声明
            它们的 定义 放 分离的 源文件, 并 `分别编译`
            
        (2) 优点
            1) 编译时间 降到最少
            2) 逻辑独立的部分 分离 => 错误几率 降到最低
            
        (3) 应用
            库: 分离编译的 代码片段 的 集合
    
        (4) 机制
        
                    模块头文件: 
                        模块(Vector) 接口
                     /          \
                    /            \
            用户源文件:      模块源文件: 
                使用 Vector       定义/实现 Vector
    
            // 1) Vector.h
            class Vector
            {
            public:
                Vector(int s);
                double& operator[](int);
                int size();
            private:
                double* elem; 
                int sz;
            };
            
            // 2) user.cpp
            #include "Vector.h"
            #include <cmath>
            using namespace std;
            double sqtr_sum(Vector& v)
            {
                // ...
            }
            
    
            // 3) Vector.cpp
            #include "Vector.h" // 获得接口
            
            Vector::Vector(int s)
                : elem {new double[s] }, sz(s) { }
            
            double& Vector::operator[](int i) { return elem[i]; }
            
            int Vector::size() { return sz; }
    

    2 名字空间

        表达一组声明 属于 一个整体
        避免 `名字冲突`
    

    3 错误处理

        (1) 异常
        
            1) 机制
                分离 运行时 错误捕获位置 与 错误处理位置
            
            2) 可 自定义 异常类
            
            3) 例子
                Vector 实现者 `检测` 异常, 通过 throw `通知` 使用者
                
                Vector 使用者 通过 catch 采取应对措施
                
            // 实现者
            double& Vector::operator[](int i) 
            {
                if(i<0 || size() <= i)
                    throw std::out_of_range("Vector::operator[]");
                return elem[i]; 
            }
            
            // 使用者
            void f(Vector& v)
            {
                try
                {
                    v[v.size()] = 10;
                }
                catch(std::out_of_range)
                {
                    // 处理
                }
            }   
            
        (2) `类的不变式`
            
            1) 含义
                假定某事为真的 声明
                
            2) 建立 类的不变式 
                1> 是 Ctor 的责任, 从而 成员函数 可以依赖于 不变式
                
                2> 确保 成员函数退出时, 不变式 仍成立
    
            Vector::Vector(int s)
            {
                if(s <0)
                    throw length_error{};
                elem = new double[s];
                sz(s);
            }
    

    相关文章

      网友评论

          本文标题:第1/2章: C++ 建议 / 两种不变性 const & co

          本文链接:https://www.haomeiwen.com/subject/itpbmrtx.html