• effect c++ 口诀。


    常用条款,写成口诀,记住。知其所以,也要时时使用。

    1)习惯c++:

    联替const初。

    2)构造,复制,析构:

    要知默,构赋析。

    若不需,明拒绝。

    构析不调虚。

    异不逃析构。

    基析要虚函。

    赋值操,每成员。返this引,注自我。

    3)资源管理

    对象管资源。

    copy资管,禁引复移。

    资管显隐源,

    new,delete,同形式

    new资入智,要原操。

    4)设计与申明

    常引用,返对象

    要返引,离开函数要存在(自己添加的条款)

    成员变量要私有。

    尽量使用外函数。

     5)实现

    延迟定义,避返内柄。(内柄:内部数据的指针,引用,迭代)

    6)继承和面向对象。

    区分is和has。

    继承非虚函,继承缺省参,绝不重新再定义。

    13.以对象管理资源

    非常明显的意图,当需要使用堆内存时,必须使用智能指针,接管资源。

    认识太浅。。资源不是说堆而已,任何东西都有可能是资源。int是资源,socket也是资源。string。也是资源。就看需不需要管理。

    栈里的变量也是资源。重要的是看需不需要管理

    1.对于堆中的资源,那么管理类,可以狭义的看成为shared_prt.

    2.对于数据库链接。那么管理类,就可以自己写个类,只要在析构上close它就好了,但是根据异常不逃析构原则,需要吞下异常,所以一般会提供close的方法,给用户手动释放资源。而我们的析构是一个保障而已。就算吞下异常,

    调用者没有显示close ,也要承担一部分责任。应该早早在close 的时候。捕获异常。

    只是,比如数据库链接,应该会做成一个单例模式。

    而有些资源,它本身在堆中放着,那么用shared_prt来管理堆中的内存。而它本身里面可能也有资源。所以他还要写析构函数来管理内部资源。

    所以对象管理资源这个准则是适合类里面的资源,和类本身相对于内存来说的自身也是资源。很有可能对于一个类的使用和设计。我们这个准则运用了2次。

    #include <iostream>
    #include "stdio.h"
    #include <memory>
    #include <unistd.h>
    #include <thread>
    #include <vector>
    #include <exception>
    
    using namespace std;
    
    
    class investment
    {
    public:
        investment(int _v):money(_v){}
        virtual int getit()const =0;
        ~investment()
        {
            try
            {
                
            }
            catch(exception &ee)
            {
                //log
                std::abort();
            }
        };
    protected:
        int money;
    };
    
    class socket:public investment
    {
    public:
        socket(int _v):investment(_v){}
        int getit()const
        {
            return investment::money*3;
        }
    };
    
    
    class zaiquan:public investment
    {
    public:
        zaiquan(int _v):investment(_v){}
        int getit()const 
        {
            return investment::money*5;
        }
    };
    
    
    void showMoney(const investment& a)
    {
        cout<<a.getit()<<endl;
    }
    
    
    class factory
    {
    public:
        shared_ptr<investment>  CreateSocket(int v)//让接口更容易被使用,不被误解。
        {
            return shared_ptr<investment>(new socket(v));
        }
        
        investment* Createzaiquan(int v)//危险行为.
        {
            return new zaiquan(v);
        }
    };
    
    
    int main()
    {
        factory investmFactory;
        shared_ptr<investment> psocket=investmFactory.CreateSocket(3);
        showMoney(*psocket);
        
        shared_ptr<investment> pzaiquan=shared_ptr<investment>(investmFactory.Createzaiquan(4));
        showMoney(*pzaiquan);
    }#include <iostream>
    #include "stdio.h"
    #include <memory>
    #include <unistd.h>
    #include <thread>
    #include <vector>
    #include <exception>
    
    using namespace std;
    
    
    class investment
    {
    public:
        investment(int _v):money(_v){}
        virtual int getit()const =0;
        ~investment()
        {
            try
            {
                
            }
            catch(exception &ee)
            {
                //log
                std::abort();
            }
        };
    protected:
        int money;
    };
    
    class socket:public investment
    {
    public:
        socket(int _v):investment(_v){}
        int getit()const
        {
            return investment::money*3;
        }
    };
    
    
    class zaiquan:public investment
    {
    public:
        zaiquan(int _v):investment(_v){}
        int getit()const 
        {
            return investment::money*5;
        }
    };
    
    
    void showMoney(const investment& a)
    {
        cout<<a.getit()<<endl;
    }
    
    
    class factory
    {
    public:
        shared_ptr<investment>  CreateSocket(int v)//让接口更容易被使用,不被误解。
        {
            return shared_ptr<investment>(new socket(v));
        }
        
        investment* Createzaiquan(int v)//危险行为.
        {
            return new zaiquan(v);
        }
    };
    
    
    int main()
    {
        factory investmFactory;
        shared_ptr<investment> psocket=investmFactory.CreateSocket(3);
        showMoney(*psocket);
        
        shared_ptr<investment> pzaiquan=shared_ptr<investment>(investmFactory.Createzaiquan(4));
        showMoney(*pzaiquan);
    }

    14,在资源管理类中小心copy行为。

    常见的资源是heap中的资源。一般常用法是用shared_ptr这个类来管理。

    而有很多资源并非是内存,可能是锁,可能是SOCKET,DB CONNECT.等等。

    堆中的资源,copy行为对于 共享指针是位拷贝。符合堆资源的要求。

    而对于其他资源,大部分是禁止COPY 的。比如锁。STL的中管理锁的类有LOCK_GURAD。对于COPY,是禁止的,因为MUTEX,本身就禁止了复制。当然管理类是不可能实现COPY 行为的。

    资源管理类对于copy有4种,禁引复移。

    禁止:就如lock_gurad,这种管理锁类的资源管理类,对于资源是禁止复制的。

    引用计数:这个就是大名鼎鼎的shared_ptr,只复制资源的指针,采用计数来确定是否删除。

    复制:代表也是大名鼎鼎的string,由于使用的惯性(习惯会认为是2个不同的字符串,修改一个对其他的没有影响),所以string,采用的是复制,而不是引用计数。

    移动,当然也是大名鼎鼎的auto_ptr

    #include <iostream>
    #include "stdio.h"
    #include <memory>
    #include <unistd.h>
    #include <thread>
    #include <vector>
    #include <mutex>
    #include <unistd.h>
    #include <stdlib.h>
    
    using namespace std;
    
    mutex mtx;
    
    class mylock_guard
    {
    public:
        mylock_guard(mutex& _mtx):mtx(_mtx)
        {
            mtx.lock();
        }
        
        ~mylock_guard()
        {
            mtx.unlock();
        }
        
    private:
        mylock_guard(const mylock_guard&);
        mylock_guard& operator=(const mylock_guard&);
        mutex& mtx;
    };
    
    
    void ShowMsg()
    {
        //lock_guard<mutex> lck(mtx);
        mylock_guard lck(mtx);
        cout<<"1 seconed"<<endl;
        sleep(1);
    }
    
    int main()
    {
        
        thread t1(ShowMsg);
        thread t2(ShowMsg);
        thread t3(ShowMsg);
        
        t1.detach();
        t2.detach();
        t3.detach();
        
        string cmd;
        cin>>cmd;
    }

     15.在资源管理类中提供对原始资源的访问。

    在shared_prt类中。提供了get(),函数支持对原始资源的访问。是属于显示支持。

    16,成对使用delete 和new 要采用相同的形式。

    new delete. new[] delete[]

    不过由于STL的存在,对于基本型。如char ,一般会使用string。string(char* ,int),基本和shared_ptr类似的管理资源。

    只是对于copy行为, 智能指针是位拷贝,属于浅拷贝(但有引用计数),而string, 属于深拷贝(无引用计数)。 

     由于STL的存在,很少会直接使用 new 和 delete .除非对性能比较敏感,比如char,可能就不使用string.而直接用CHAR*来做缓存类。那么就必须手动 new 和 delete.

    17,以独立语句将newd 的资源放入资源管理类。

    这个如何理解,就是根本上,NEW了资源,第二部就是给资源管理类。

    我们细细想下,进入一个函数,栈空间已经开辟,所以资源管理类是不会出错的。比如是共享指针。

    那么可能异常的只有NEW资源,当NEW资源失败,那也没有造成内存泄露。

    只要NEW 正常。那么共享指针就接管了资源。行为完全正确。

    而假如 initme(shared_ptr<> a,  int)

    调用时,却采取   initme(shared_ptr<t>(new T()),  foo());

    由于编译器的问题。很可能,foo()  的执行会插在NEW之后,而这个时候,资源管理类还没有接管资源哦, 如果 FOO出错。那么NEW 的资源就泄露了。

    所以正确的行为是

    shared_ptr<t> pt (new T());

    initme(pt,  foo());

    18,设计与申明。

    18. 让接口,简单,不易误解。

    比如如果返回堆中对象,可以是指针或者智能指针,返回栈中队形,则必须是对象。

    而返回堆中对象,可以优先选择智能指针,这样迫使客户使用时,建立智能指针对象来接受。避免客户的疑惑和忘记删除。但是google 的 protobuf ,却为了性能,使用了自己的资源管理类,返回的是指针。

    19.设计class 犹如设计type.

    任务太艰巨,只能实践中检验,先放下。

    20,以const by ref替换by value.

    1,性能的考虑,BY VALUE,需要COPY构造和析构,这还不包括里面是否有对象需要构造和析构。

    2.继承,如果参数是基类,那么传递派生类。会进行切割。

    3.可以BY VALUE传递的是内置类型,迭代器和函数对象。

    迭代器在VECTOR中,其实就是元素指针的别名。而函数对象,一般会比较少而且是内置类型的内部成员,

  • 相关阅读:
    深度优先和广度优先搜索
    宏定义
    C++11新特性之七——final/override控制
    __declspec的用法
    zedboard学习(1)OLED驱动显示图像
    python+NLTK 自然语言学习处理三:如何在nltk/matplotlib中的图片中显示中文
    流畅python学习笔记第十八章:使用asyncio编写服务器
    流畅python学习笔记第十八章:使用asyncio包处理并发(二)
    Django之博客系统:自定义认证
    Django之博客系统:用户注册和Profile
  • 原文地址:https://www.cnblogs.com/lsfv/p/6035747.html
Copyright © 2020-2023  润新知