《c++编程剖析-问题,方案和设计准则》笔记

1vector的使用

  • 我们只可以使用operator[]和at()去改动那些已经存在于容器中的东西. 而 用reserve()函数不会使得容器中充满函数,需要用resize()函数代替
  • 当不对容器内的元素做任何改动时,记得使用const_iterator

2关于标准成员函数

  • C++标准库的实现中的成员函数签名并不要求与标准中说明的函数签名一模一样,它可以具有额外的默认函数. 这意味着,不同的标准库的成员函数签名可能不一致. 这也意味着,不存在一个可移植的指向标准库成员函数的指针. 同时也意味着不可能可移植地对标准库成员函数使用mem_func和mem_func_ref仿函数

3当使用泛型来定义泛型时,注意被用来定义的那个泛型是否足够泛化

template<class T>
void destroy(T* p)              // 注意这里的泛型要求是一个指针
{
  p->~T();
}

template<class Fwdlter>
void destroy(Fwdlter first,Fwdlter last) // 注意这里的泛型只要求是个迭代器就行
{
  while(first != last)
    {
      destroy(first);           // 这里的泛化就不够
      ++first;
    }
}

4函数匹配的规则

  1. 在参数匹配一样好的情况下优先使用普通函数. 这里要注意的是只有在参数匹配一样好的情况下才会选择普通函数.例如

    /*
    有一个Base类,有Sub1和Sub2子类,这两个子类有一个共同的属性
    public string sName;
    现在我定义一个模板函数
    */
    template<class T>
    void say(T t)
    {
        cout<<t.sName;
    }
    //但是同时我可能也定义了一个函数
    void say(const string& sName)
    {
        cout<<sName;
    }
    /*
    这时,如果我用一个字符数组调用函数say("darksun");
    这时C++会匹配模板函数,而不是const string的这个函数.
    */
    
  2. 选择匹配性最好的主函数模板
  3. 选择好了的主函数模板中查看是否有特化的函数模板. 这里要注意的是,只有在某个主模版被选定的情况下,其特化版本才可能被使用,也就是说,模板特化并不参与重载选择
    template<class T>
    void f(T);                      // 主模板a
    
    template<>
    void f<int*>(int*);             // 对主模板a的特化模板b
    
    template<T>
    void f(T*);                     // 主模板c,是主模板a的重载
    
    int *p;
    f(p);                           // 这时会调用主模板c! ,因为在第2步挑选主模板是,就选择了该重载的模板
    

5关于export

  • 目前大多数的编译器实现都不支持export,因此要编写可移植的代码,就别用export
  • export的最初目的是想实现分离式的模板编译,然而现阶段编译器的实现无法做到这一点,实际上还是需要提供模板的实现代码。

6异常规格

  • 编译器会自动对待了异常规格的函数添加try catch代码,而这增加了运行时开销。 例如

    int Hunc throw(A,B)
    {
      return Junc();
    }
    // 实际上编译器会自动生成类似如下的代码
    int Hunc
    {
      try{
        return Junc();
      }
      catch(A)
        {
          throw;
        }
      catch(B)
        {
          throw;
        }
      catch(...)
        {
          std::unexpected();
        }
    }
    

    而且即使函数体内实际上并不会抛出异常,编译器也会生成try catch块,因此,永远不要为函数加上异常规格

7类成员函数的查找规则

  1. 选择作用域.

    编译器先寻找一个至少包含指定名函数的作用域,并将其中的所有同名函数列出作为候选列表. 这意味着在子类中重载父类的方法会掩盖父类的所有同名方法

  2. 在候选的同名函数中选择适当的最佳匹配
  3. 最后进行可访问性的检查.这意味着即使父类中有可访问的同名函数,也不会被访问到

8NVI(Nonvirtual Interface,非虚接口)模式

  • NVI模式是指类的接口应该是稳定的,因此可以定义为非虚函数的形式. 而接口的实现是可变的,因此定义接口实现函数为虚函数. 在非虚的接口中调用虚拟的接口实现函数. 这样的设计类似于设计模式中的模板方法,其好处在于提供了一个统一的入口可以方便在一个单一的地方实施接口的前置条件和后置条件.

9关于new操作符

9.1new操作符的几种形式

标准版new的相互比较
new类型 定义形式 是否进行内存分配 是否可能失败 是否抛出异常 是否可替换
简单new void* ::operator new(std::size_t size) throw(std::bad_alloc); 是,抛出异常 std::bad_alloc
nothrow new void* ::operator new(std::size_t size,const std::nothrow_t &) throw(); 是,返回null
定位new void* ::operator new(std::size_t size,void* ptr)throw();
其他类型的new void* ::operator new(std::size_t size,其他任意参数…);
类相关的new void* Class::new(std:size_t size,…)

9.2new操作符的选择机制(类似类成员函数的查找机制)

  1. 选择作用域

    编译器先从子类作用域中查找operator new,再从基类,然后全局查找. 一旦找到有任何一种operator new定义就停止查找,而只在该作用域内查找operator new操作. 这意味着再往外层的作用域就不予考虑了.

  2. 选择合适的重载operator new函数
  3. 检查合适的operator new函数的访问规则是否允许访问.

9.3避免使用nothrow new

这是因为:

  1. 可能会忽略检查nothrow new的返回值,从而掩盖失败
  2. 在某些操作系统实现上,直到内存实际被使用时才会申请. 这是new永远不会返回失败,但是在后面对内存的操作语句中,每一句都可能失败.
  3. 在拥有虚拟内存的系统上,new几乎不会失败,因为在虚拟内存耗尽之前,系统就已经很慢了,然后系统操作员就开始杀掉一些进程了.
  4. 即使真的检测到了new失败,由于内存已经所剩不对了,你也几乎做不了什么,只能让程序退出.

10类定义中using语句的局限

在一个类的定义内部,你只可以通过using声明来带入基类中的名字,而不能带入诸如全局名字或其他类中的名字.

11如果一段代码能够解释为声明,他就被解释成声明

在声明和表达式语句这两者的语法形式之间可能会出现二义性:一个函数风格的显式类似转换(exp.type.conv)作为其最左端的子表达式的表达式语句和一个其第一个声明子(declarator)以"("开头的声明语句可能无法区分开. 在这种情况下,该语句被解释为声明.

例如

deque<string> coll2(coll1.begin(),coll1.end());
deque<string> coll3(istream_iterator<string>(cin),istream_iterator<string>());
// 上面这句话本意是定义一个coll3,类型为deque<string>,其初始值从cin取得.

// 然而编译器会认为这是声明了一个名为coll3的函数,其返回deque<string>. 他有两个参数,一个参数名为cin,类型为istream_iterator<string>. 另一个参数没有名字,类型也为isteram_iterator<string>

12当心注释中的三字符组和二字符组

所谓三字符组(trigraph)是指3个字符组成的转义符,比如"??/"="\","??!"="~". 类似的还有二字符组,比如":>" = "]" 举个例子:

// 这里的注释,包含了几行的内容??/
第二行其实也被注释了,因为第一行的"??/"被解释为"/",这个转义符把接下来的换行符吃掉了...

Date: 2014-05-15T22:38+0800

《c++编程剖析-问题,方案和设计准则》笔记,布布扣,bubuko.com

时间: 2024-08-04 23:25:26

《c++编程剖析-问题,方案和设计准则》笔记的相关文章

SQL 笔记 By 华仔

-------------------------------------读书笔记------------------------------- 笔记1-徐 最常用的几种备份方法 笔记2-徐 收缩数据库的大小的方法 笔记3-徐 设置数据库自动增长注意要点 笔记4-徐 模仿灾难发生时还原adventurework数据库 示例 stopat 笔记5-徐 检查日志文件不能被截断的原因 笔记6-徐 检测孤立用户并恢复孤立用户到新的服务器 解决数据库镜像孤立用户问题 笔记7-徐 SQLSERVER日志记录

SQL笔记---多表左联

这是实际场景当中的一个例子,拿出来分析总结思路. -- SQL 查询 --SELECT  orderQuery.Rk_SkuCode ,        orderQuery.SkuName,        SUM(ISNULL(orderQuery.OrderTotal, 0))        - SUM(ISNULL(removeQuery.RemoveTotal, 0))        - SUM(ISNULL(pickQuery.PickTotal, 0))        - SUM(IS

SQL笔记---分页

随用随想,随用随记. 通过实际应用掌握SQL语句. 一. SQL分页 1. 第一种方法:利用ID大于多少进行筛选 SELECT TOP 20        *FROM    dbo.WMS_StockWHERE   ( Rk_SkuCode > ( SELECT MAX(Rk_SkuCode)                         FROM   ( SELECT TOP 40                                            *           

《HeadFirst SQL》笔记

规范化 0 约束 1 原子性 2 第一范式 1NF 3 数据模式 4 依赖 5 联接查询 6 交叉联接(AKA 笛卡尔联接,叉积) 7 内联接 8 子查询 9 外联接 10 自联接 11 集合 12 事务 13 ACID 14 管理事务 15 常用语句 16 注意 17 规范化 约束 NOT NULL UNIQUE PRIMARY KEY DEFAULT FOREIGN KEY:引用父表的某个唯一值引用完整性:插入外键列的值必须已经存在于父表的来源列中 --创建外键 create table i

SQL笔记1:SELECT及SELECT高级应用

T-SQL笔记1:SELECT及SELECT高级应用 本章摘要 1:安装AdventureWorks 2:基本运算符和表达式 3:between 4:like 5:escape 6:TOP 7:GROUP BY 7.1:GROUP BY ALL 7.2:HAVING 8:SELECT字句技术 8.1:使用DISTINCT消除重复值 8.2:返回拼接的结果 8.3使用INTO字句 9:子查询 9.1:子查询类型 9.2:代替表达式的查询 9.3:多层嵌套 10:比较使用 EXISTS 和 IN 的

金典 SQL笔记(6)

page223-索引 --利用SQL 语句创建索引 --CREATE INDEX 索引名称on 表名(字段 ,字段, 字段字段n) --索引名称必须为唯一的,字段 ,字段, 同意一个到多个 --范例为T_person 表中给FName创建索引索引名为 idx_person_name CREATE INDEX idx_person_name ON T_Person (FName) --删除索引 --drop index 表名索引名 DROP INDEX T_person.idx_person_na

Mybatis 项目开发实际常用SQL笔记总结

parameterType 和 resultType parameterType:单个参数用String,多个参数用map resultType:   可以是 Integer.String.Object    <select id="countGroupMasterByUid" parameterType="String" resultType="Integer">      SELECT              COUNT(id)

sql笔记/分页存储过程

[email protected]c#中进行++操作可以是整数或小数,sql中只能对整数进行++操作.char类型 适合存储长度波动较小不回收效率高varchar 类型 适合存储长度波动较大可以回收nchar代表unicode 存储内容包括汉字时候考虑加n SQL语句特点1不区分大小写2没有双引号所有字符串都包含在单引号3没有逻辑相等,逻辑相等和赋值一样都是用=4没有bool值得概念,但是在视图中可以输入true/false5也有关系运算符.6也有逻辑运算符 &&-- and || --o

sql笔记

1. 看下面sql,重点有两个,一个是distinct  ,一个是树形结构查询 select DISTINCT t.unit_code from t_unit_relation t where t.corp_tn='jiaozhougongan' start with t.unit_code='0001' connect by prior t.unit_code = t.unit_upcode 分析: ① distinct:去重复值 ② 树形结构查询,这个博客:http://www.cnblog

HeadFirst SQL 读书摘要

数据库都是用 圆柱形表示的. 数据库中包含表 表中包含行和列 行又叫记录record,  列又叫 字段field 创建数据库 create database mypipe_l; 选择数据库 use mypipe_l; 创建表 create table doughnut( name VARCHAR(10), type VARCHAR(6) ); 查看表 desc doughnut; 删除表 drop table doughnut; 插入数据 insert into doughnut (name,