//---------------------------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. jmeter函数简介

    1._char:把一组数字转化成Unicode字符. 2._counter:记录线程的迭代次数. 3._CSVRead:可以从文件中指定列的值. 4.${_CSVRead(D:\test.txt,0, ...

  2. w3school 基础学习

    http://www.w3school.com.cn/ http://www.w3school.com.cn/sql/sql_quickref.asp

  3. Automation Script For Percona Xtrabackup FULL/Incremental

    This is my first post in 2019, and Im starting with a MySQL solution. In MySQL world, implementing a ...

  4. 从外部导入django模块

    import os import sys sys.path.append("D:\\pyweb\\sf"); # 项目位置(不是app) os.environ.setdefault ...

  5. linux date 简单介绍

    用法:date [选项]... [+格式] 或:date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]] 以给定的格式显示当前时间,或是设置系统日期. - ...

  6. Spring Cloud 子项目介绍

    Spring Cloud由以下子项目组成. Spring Cloud Config 配置中心——利用git来集中管理程序的配置. 项目地址:https://spring.io/projects/spr ...

  7. 第四次作业 重写equals方法

    使用上几次用到得User实体类,在其中重写equals方法. @Override public boolean equals(Object obj) { if(obj==null)return fal ...

  8. 一次SQLServer数据库宕机问题

    数据库采用SQL Server 2005版本, 数据库文件约为6G,而LDF日志文件已经高达36G. 服务器开始变的不太稳定 .数据没有成功保存. 打开事件查看器发现很多信息日志 数据库 '' 中的文 ...

  9. 三、git管理修改

    一.修改提交 如下图,Git分工作区和版本库(.git隐藏目录中). 在每次修改后 git add "file name" 其实是把修改内容提交到本地版本库的 暂存区(stage) ...

  10. requirejs原理深究以及r.js和gulp的打包【转】

    转自:http://blog.csdn.net/why_fly/article/details/75088378 requirejs原理 requirejs的用法和原理分析:https://githu ...