//---------------------------15/03/26----------------------------

3:const函数的哲学思辨:就当是科普知识吧!如果成员函数是const意味着什么?

这里有两个流行的概念:

1>bitwise(按位) constness(const + ness ==const的名词)又称physical constness

这个阵营的人相信,只有不改变对象的任何一个bit的函数才可以称为const函数,但是很多成员函数

并不具备const性质却能通过bitwise测试。

class CTextBlock

{

public:

...

char& oprator[](std::size_t position) const

{ return pText[position];}

private:

char* pText;

};

这个class不适当地将其operator[]声明为const函数,

而该函数却返回了一个reference指向对象内部值,

下面的代码可以很容易修改对象值

const CTextBlock cctb("hello");

char* pc = &cctb[0];

*pc = 'J';

上面的代码并没有出错,而且成功更改了对象的pText指针指向的内容

//总结:bitwise派别认为只要 const成员函数自己不改变对象的内容就算const

//至于通过我返回的返回值更改我的内容,那就没意见了

2>logical constness。这一派主张,一个const成员函数可以修改它所处理的对象内的某些bits,

但只有在客户端侦测不出的情况才得如此。如下

class CTextBlock

{

public:

std::size_t length() const;

private:

char* pText;

std::size_t textLength;

bool lengthIsValid;

};

std::size_t CTextBlock::length() const

{

if(!lengthIsValid)

{

textLength = std::strlen(pText);

lengthIsValid = true;

}

return textLength;

}

上面对textLength
和 lengthIsValid 的赋值都是错误的,因为在const成员函数中不能给它们赋值

所以应该在这两个变量的声明前加上mutable

小总结:本书也没有说出logical constness的意义在哪里,本来我看到logical的理解是,严格意义上

的“const”也就是不能修改对象,也不能返回
能修改对象的引用或指针。没想到logical竟然是允许修改

客户端侦测不到情况下的对象变量。

4:在const和non_const成员函数中避免重复

当一个成员函数很长时,const版本和non_const版本的成员函数会有很多重复的内容:

class TextBlock

{

public:

const char& operator[] (std::size_t position) const

{

...     //边界检验

...     //日志记录访问

...     //检验数据完整性

return text[position];

}

char& operator[] (std::size_t position)

{

...     //边界检验

...     //日志记录访问

...     //检验数据完整性

return text[position];

}

private:

std::string text;

};

上面的代码有很多重复的地方,所以我们要实现operator[]的机能一次,然后使用两次。也就是让其中一个

调用另外一个。

由于会进行状态的改变从const转到non_const或者反向转化,所以不能使用const版本调用non_const版本

因为const版本承诺不改变状态,所以就要使用non_const版本调用const版本,通过static_cast和

const_cast进行转化。

class TextBlock

{

public:

const char& operator[] (std::size_t position) const

{

...     //边界检验

...     //日志记录访问

...     //检验数据完整性

return text[position];

}

char& operator[] (std::size_t position)

{

return const_cast<char&>(

static_cast<const TextBlock>(*this)

[position]

}

private:

std::string text;

};

上面const_cast的目的是为了去除const属性,static_cast的目的是为了正确调用const版本的operator[]

成员函数,不然就会无限调用本身,陷入死循环。

*/

}

//#4    确定对象呗使用前已经被初始化

{

/*

关于这点相信很多人都吃过苦头,但是还是常常会忘记

来自c的部分一般都不保证其内容被默认初始化就像数组(array)

而来自非c的部分一般都保证了初始化,就像vector。

最好的处理就是,对所有的对象在使用前都初始化。

1:关于构造函数的赋值和初始化:

构造函数在函数名后面加  : 然后跟上初始化内容,这样写就是初始化,而且比赋值效率高

如果写在{}中,那样就是赋值了,看一下例子

ABEntry::ABEntry(const std::string& name,

const std::string& address):theName(name)

{

theAddress=address;

}

theName就是初始化,theAddress就是赋值。前者效率更高,这是因为在调用构造函数的

时候,会为theName和 theAddress设置初始值,如果不是在初始化就设置而是在之后

更改,效率自然就低了.

2:一般来说最好都适用成员初值表来给定初始值。但是也有一种情况就是,一个类存在很多

构造函数,每个构造函数都需要初始化成员变量,那么为了减少工作量,也可以使用某个函数

来给定“初始值”其实就是赋值了。

3:这里讲了很重要的点,成员初始化次序,(之前的腾讯在线笔试题刚好做到了),成员初始化

次序总是相同的,base classes更早于其derived classes被初始化,而class的成员变量

总是以其声明次序被初始化。总结来说次序是这样的root class(继承中的最老的那个类)按声明

次序初始化成员变量,root class的子类按顺序...
自己这个类按声明次序初始化成员变量

所以在列成员初值表时,最好按声明顺序列出

4:不同编译单元内定义的non_local static对象的
初始化次序

static对象的寿命从被构造出来直到程序结束为止,这种对象包括global对象,定义与namespace

内的对象,在class内,函数内,以及在file作用域内被声明为static的对象

如果我们要使用这些对象,初始化次序就显得很重要:

class Directory

{

public:

Directory(params);

};

Directory::Directory( params)

{

std::size_t disks = tfs.numDisks();

}

Directory tempDir(params);

上面的tfs是一个non_local static对象

这时tfs就必须要先于tempDir被初始化,不然tfs都还没初始化就拿来用会发生不可预期的问题;

我们可以采用单例模式来解决这个问题:

class FileSystem{...};

FileSystem& tfs()

{

static FileSystem fs;

return fs;

}

有了这个函数,当需要使用FileSystem对象时,只要调用tfs()就可以了

上面的构造函数可以改成 std::size_t disks = tfs().numDisks();

有了tfs函数,当需要使用时就会先初始化tfs对象然后返回。

补充,单例模式应该写成如下形式:

class FileSystem

{

...

private:

Filesystem(){}; //让构造函数为私有的,这样才能保证单例

};

FileSystem& tfs()

{

static FileSystem* fs;

if(fs == NULL)

fs= new FileSystem;

return fs;

//加上if判断是为了懒加载,到了用的时候再创建出这个对象,不然会浪费内存

}

总结:采用non_const static对象不管是local还是non_lacol在多线程下都不安全

方法有两个:

1>在单线程时手动调用tfs()

2>使用互斥锁来加解锁;

*/

}

effective c++ 笔记 (3-4)的更多相关文章

  1. Effective Java笔记一 创建和销毁对象

    Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...

  2. [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

    js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...

  3. [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符

    “1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...

  4. [Effective JavaScript 笔记]第3章:使用函数--个人总结

    前言 这一章把平时会用到,但不会深究的知识点,分开细化地讲解了.里面很多内容在高3等基础内容里,也有很多讲到.但由于本身书籍的篇幅较大,很容易忽视对应的小知识点.这章里的许多小提示都很有帮助,特别是在 ...

  5. [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

    函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...

  6. [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法

    js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...

  7. java effective 读书笔记

    java effective 读书笔记 []创建和销毁对象 静态工厂方法 就是“封装了底层 暴露出一个访问接口 ” 门面模式 多参数时 用构建器,就是用个内部类 再让内部类提供构造好的对象 枚举 si ...

  8. Effective STL 笔记 -- Item 6 ~ 7: Container and Object Pointer

    Effective STL 笔记 – Item 6 ~ 7: Container and Object Pointer 中间两次笔记被删掉了,简单补一下: Item 3 中提到如果将对象直接放入容器中 ...

  9. Item 5:那些被C++默默地声明和调用的函数 Effective C++笔记

    Item 5: Know what functions C++ silently writes and calls 在C++中,编译器会自己主动生成一些你没有显式定义的函数,它们包含:构造函数.析构函 ...

  10. effective c++ 笔记 (1-3)

    // //  effective c++.cpp //  笔记 // //  Created by fam on 15/3/23. // // //-------------------------- ...

随机推荐

  1. IE 出现stack overflow 报错的原因归纳

    1. 重定义了系统的触发事件名称作为自定义函数名如:  onclick / onsubmit ...  都是系统保留的事件名称,不允许作为重定义函数名称: 2. IE缓存满了,无法写入.解决办法:清空 ...

  2. 实现CTreeCtrl父子节点的联动选择

    本文实现了下面的功能: 当选中父节点时, 其所有子节点全部选中. 当取消选中父节点时, 其所以子节点全部取消选中. 点击子节点时, 根据子节点与其兄弟节点的选中状态, 自动设置父节点的选中状态. 通过 ...

  3. selenium-键盘和鼠标事件

    常见的键盘操作 from selenium.webdriver.common.keys import Keys 模拟enter键:send_keys(Keys.ENTER)键盘F1~F12: send ...

  4. C# 生成随机订单号

    //生成固定位数的随机数 //ran.Next(999)生成的是1-999的随机数,不能保证位数是固定的. public static string GenerateOrderNo()        ...

  5. Alpha冲刺报告(9/12)(麻瓜制造者)

    今日已完成 邓弘立: 正在进行主页逻辑的编写 符天愉: 部署商品发布和物品需求的接口 江郑: 尝试完善接口文档,进行进一步测试 刘双玉: 编写接口说明 肖小强: 进行逻辑模块的编写 李佳铭: 修改了U ...

  6. sed 指定行范围匹配(转)

    sed -n '5,10{/pattern/p}' file sed是一个非交互性性文本编辑器,它编辑文件或标准输入 导出的文件拷贝.标准输入可能是来自键盘.文件重定向.字符串或变量,或者是一个管道文 ...

  7. .Net使用163smtp发送邮件时错误:邮箱不可用. has no permission解决方法

    C#实现简单邮件发送代码如下 public static void SendAsync(string emailTo, string subject, string mailBody) { var m ...

  8. 设置webstorm支持ES6语法

    1.  点击File目录下的Default Settings 2.  再依次点击Languages & Frameworks  ----->  JaveScript  ----> ...

  9. Zookeeper入门(二)之基础

    在深入了解ZooKeeper的运作之前,让我们来看看ZooKeeper的基本概念.本文主要包含如下内容:1.Architecture(架构)2.Hierarchical namespace(层次命名空 ...

  10. jmeter接口测试4-使用数据库mysql构造参数

    jmeter测试中,测试数据一般和测试用例分离 测试数据一般可以使用csv构造,进行参数化 但也可以使用mysql等数据库构造 方案一:一个线程循环调用mysql数据,不是并发,不适用于性能测试,更适 ...