zoukankan      html  css  js  c++  java
  • effective c++ 笔记 (3-4)

        //---------------------------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:constnon_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>使用互斥锁来加解锁;

         

         

         

         

         

         

        */

        

    }

  • 相关阅读:
    hdu
    《Linux命令行与shell脚本编程大全》 第十四章 学习笔记
    zoj 3665 Yukari's Birthday(枚举+二分)
    ActiveMQ使用STOMP协议的一个错误问题:Unexpected ACK received for message-id
    Ubuntu下屏幕录像、后期处理不完全攻略
    find-all-numbers-disappeared-in-an-array
    find-right-interval
    non-overlapping-intervals
    cut命令如何截取以空格隔开的字段
    arranging-coins
  • 原文地址:https://www.cnblogs.com/boydfd/p/4983160.html
Copyright © 2011-2022 走看看