zoukankan      html  css  js  c++  java
  • effective C++ 读书笔记 条款08

    条款08  别让异常逃离析构函数:

    假设在析构函数其中发生了异常,程序可能会过早结束或者导致不明白行为(异常从析构函数传播出去)

    看代码:

    #include <iostream>
    using namespace std;
    
    
    class DBConnection
    {
    public:
    
    
    	void close()
    	{
    			int i = 3;
    			int j = 0;
    			int k = i/j;
    			printf("%d
    ",k);
    	}
    };
    
    class DBConn
    {
    public:
    	DBConn()
    	{
    
    	}
    
    	/*
    	~DBConn()
    	{
    			db.close();
    	}
    	*/
    
    
    
    	//解决的方法1:强迫结束程序
    	
    	~DBConn()
    	{
    		try
    		{
    			db.close();
    		}
    		catch(...)
    		{
    			abort();//假设一个程序遭遇一个“于析构期间发生的错误”后无法继续同意,强迫结束是个合理的选择。用abort阻止异常从析构函数传播出去
    		}
    	}
    	
    
    
    	//解决的方法2:吞下异常
    	/*
    	~DBConn()
    	{
    		try
    		{
    			db.close();
    		}
    		catch (...)
    		{
    			//制作运转记录,记下对close的调用失败
    		}
    	
    	}
    	*/
    private:
    	DBConnection db;
    };
    
    
    int main()
    {
    	DBConn dbc;
    	//dbc对象销毁时会自己主动调用DBConnection的close函数;仅仅要调用close成功,一切美好,可是假设该调用出现异常。DBConn析构函数
    	//会传播该异常。也就是同意它离开这个析构函数。

    会造成问题。

    return 0; } /* 採用本来的析构函数: 执行程序。提示一个程序已经停止工作(感觉这里编译器优化到解决方式1了,自己主动做了处理),假设不停止工作。也出现了不明白行为。

    採用解决方式1: 执行程序,提示一个debug error,终止程序。 採用解决方式2: 执行程序,程序执行通过。可是也不会打印k的值 */


    上面的解决方式1和2。都导致对close抛出的异常无法处理:

    最佳办法就是DBConn自己又一次设计一个close接口,使得程序猿能够自己调用:

    #include <iostream>
    using namespace std;
    
    
    class DBConnection
    {
    public:
    
    
    	void close()
    	{
    			int i = 3;
    			int j = 0;
    			int k = i/j;
    			printf("%d
    ",k);
    	}
    };
    
    class DBConn
    {
    public:
    	DBConn()
    	{
    
    	}
    	~DBConn()
    	{
    		if (!closed)
    		{
    			try  //关闭连接。假设客户不那么做的话
    			{
    				db.close()
    			}
    			catch(...)
    			{
    				//在这里结束程序或者吞下异常
    			}
    		}
    
    	}
    
    	void close()
    	{
    		db.close();
    		closed = true;
    	}
    
    
    private:
    	DBConnection db;
    	bool closed;
    };
    
    
    int main()
    {
    	DBConn dbc;
    	//dbc对象销毁时会自己主动调用DBConnection的close函数;仅仅要调用close成功,一切美好,可是假设该调用出现异常,DBConn析构函数
    	//会传播该异常,也就是同意它离开这个析构函数。会造成问题。
    
    
    	return 0;
    }
    
    /*
    
    这种方法把调用close的责任从DBConn析构函数手上移动到DBConn客户手上(但DBConn析构函数仍含有一个“双保险”调用).
    
    假设某个操作可能在失败时抛出异常。而又存在某种须要必须处理该异常,那么这个异常必须来自析构函数以外的某个函数
    由于析构函数吐出异常,总会带来“过早结束程序”或者“发生不明白行为”的风险。

    这里由客户自己调用close函数。假设发现异常,能够处理。 总结: 1:析构函数绝对不要吐出异常,假设一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉该异常,然后吞下它们(不传播)或结束程序 2:假设客户须要对某个操作函数执行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非析构函数)执行该操作。 */

    1:析构函数绝对不要吐出异常。假设一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉该异常。然后吞下它们(不传播)或结束程序

    2:假设客户须要对某个操作函数执行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非析构函数)执行该操作。
     

  • 相关阅读:
    Python 模块chardet安装 setup.py
    Windows下Python安装lxml
    intellij idea 如何更改比编辑器文本字体和大小
    [转]C#设计模式(8)-Builder Pattern
    [转]C#设计模式(4)-Simple Factory Pattern
    [转]C#委托的异步调用
    [转]浅谈C#中常见的委托
    C# 线程池
    [转]C#中的委托和事件(续)
    C#(.net)中的DllImport
  • 原文地址:https://www.cnblogs.com/yxwkf/p/5418786.html
Copyright © 2011-2022 走看看