E c++ 笔记

来源:互联网 发布:ccf工资计算java 编辑:程序博客网 时间:2024/06/14 06:48

今天看了E c++总结如下:

(1) 别让异常逃离析构函数

(2) 自定义类型要考虑自我赋值的处理方法

(3)singleton模式处理初始化问题

(4) 不想编译器的默认行为要明确拒绝

(5)应对资源管理的copying行为的四种方式

这几个点感觉让我学到很多东西,下面一一详细介绍如下:

 

第一:别让异常逃离析构函数的应用场合是析构函数在执行时抛出异常的时候会导致必要的操作没有做。比如释放资源,关闭数据库连接等等。。。

class DBConnection {

public: ...

static DBConnection create();

void close();

};

 

class DBConn {

public :...

~DBConn() { db.close();}

private: DBConnection db;

};

如果客户写下:DBConn dbc(DBConnection::create());

这样可以确保db.close()总被调用,但是如果这个过程抛出异常呢?

很明显异常会逃离析构函数导致不明确行为。

三种处理方案:

1.强行终止

DBConn::~DBConn(){

try {db.close();}

catch(...){ 记录调用close失败;

std::abort();

}

}

2.吞下异常

同上,但不调用abort函数。不推荐这种行为。。。问题依然存在。。。

3.把第一处理权交给用户,再按照前面两种方法做

class DBConn{

public:...

void close(){

db.close();

closed=true;

}

~DBConn(){

if(!closed){

try{db.close();

}

catch(...){

记录调用异常; //调用异常或者终止

...

}

}

}

private: DBConnection db;

bool closed;

}

该方案就是把第一处理权给用户,用户不处理那就后面的行为用户也没意见了。。。

2.自我赋值的处理

例如  a[i]=a[j],*pa=*pb;

他们都是自己定义的同一个对象时要防止发生不明确行为

 

例如有代码:

class A{}

class B{

private:A*pb;

};

 

B& B::operator=(const B&rhs){

delete pb;

pb=new A(*rhs.pb);

return *this;

}

看似没有什么问题,其实不具备异常安全性,如果pb跟rhs指向同一个对象呢?

 

解决办法:

1.在前面加一个证同测试

B& B::operator=(const B&rhs){

if(pb==rhs.pb) return *this;

delete pb;

pb=new A(*rhs.pb);

return *this;

}

这样做B还是会有一个指针指向一块已删除的A。这样的指针是有害的。

2.改改代码就行了:

B& B::operator=(const B&rhs){

A*porig=pb;

pb=new A(*rhs.pb);

delete porig;

return *this;

}

这种方法效率可能差一些

3.copy and swap技术

class A{

...

void swap(A& rhs)

...};

A& A::operator=(const A& rhs){

A temp(rhs);

swap(temp);

return *this;

}

 

另一版本:

A& A::operator=( A rhs){

swap(temp);

return *this;

}

本来想一口气说完今天学的五个点的,只能明天了,要断网了。。。囧。。。

3.singleton模式处理初始化问题
这个问题源于C++对不同编译单元的non-local-static对象的初始化次序无明确定义
例:class A {...std::size_t test()const;}
    extern A ta;
    class B {
    public: B(params);...};
    B::B(params){...std::size_t disks = ta.test();}
若用户写下  B tb(params);将导致可能ta还没有初始化的时候就使用了ta。。。
一个简单的处理方法:
class A {...std::size_t test()const;}
A ta(){static A fa;return fa;}
class B {
    public: B(params);...};
    B::B(params){...std::size_t disks = ta().test();}
B& tb(){static B t;return t;}
其实就是用local static 替换non local static
4.不想用编译器的函数就拒绝
在了解C++的默认行为之后,如果不想按照编译器的意思来,就自己写一个,并明确拒绝编译器的行为。
自定义类类型的时候,C++会默认生成构造,析构,赋值,和复制函数。不想要拒绝之。。。
引入一个拒绝复制的类,很好用
class A
{
   protected: A(){}
               ~A(){}
private:
A(const A&);
A& operator=(const A&);
};
如果定义一个类B,防止复制行为,很简单。。。
class B:private A
{};
ok了。。。
还有构造函数什么的,可用于定义不能继承的类。。。只需将构造函数私有化。。。
5.资源管理类中的copying行为
(1)禁止复制,按如上的方法即可做到
(2)对底层资源引用计数
tr1::shared_ptr就是这么做的
(3)复制底部资源
 类似于深度复制的行为
(4)转移底部资源的控制权
tr1::auto_ptr的行为就是这样。。。

原创粉丝点击