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中,其实就是元素指针的别名。而函数对象,一般会比较少而且是内置类型的内部成员,

原文地址:https://www.cnblogs.com/lsfv/p/6035747.html