精华内容
下载资源
问答
  • C++ throw

    2020-03-19 09:58:33
    我们知道C++ 异常处理的流程,具体为: ...在 C++ 中,我们使用 throw 关键字来显式地抛出异常,它的用法为: throw exceptionData; exceptionData 是“异常数据”的意思,它可以包含任意的信息...

    我们知道C++ 异常处理的流程,具体为:

    抛出(Throw)--> 检测(Try) --> 捕获(Catch)
    

    异常必须显式地抛出,才能被检测和捕获到;如果没有显式的抛出,即使有异常也检测不到。

    在 C++ 中,我们使用 throw 关键字来显式地抛出异常,它的用法为:

    throw exceptionData;
    

    exceptionData 是“异常数据”的意思,它可以包含任意的信息,完全有程序员决定。exceptionData 可以是 int、float、bool 等基本类型,也可以是指针、数组、字符串、结构体、类等聚合类型,请看下面的例子:

    char str[] = "http://c.biancheng.net";
    char *pstr = str;
    
    class Base{};
    Base obj;
    
    throw 100;  //int 类型
    throw str;  //数组类型
    throw pstr;  //指针类型
    throw obj;  //对象类型
    

    一个动态数组的例子

    C/C++ 规定,数组一旦定义后,它的长度就不能改变了;换句话说,数组容量不能动态地增大或者减小。这样的数组称为静态数组(Static array)。静态数组有时候会给编码代码不便,我们可以通过自定义的 Array 类来实现动态数组(Dynamic array)。所谓动态数组,是指数组容量能够在使用的过程中随时增大或减小。

    使用异常示例。

    #include <iostream>
    #include <cstdlib>
    using namespace std;
    
    //自定义的异常类型
    class OutOfRange{
    public:
        OutOfRange(): m_flag(1){ };
        OutOfRange(int len, int index): m_len(len), m_index(index), m_flag(2){ }
    public:
        void what() const;  //获取具体的错误信息
    private:
        int m_flag;  //不同的flag表示不同的错误
        int m_len;  //当前数组的长度
        int m_index;  //当前使用的数组下标
    };
    
    void OutOfRange::what() const {
        if(m_flag == 1){
            cout<<"Error: empty array, no elements to pop."<<endl;
        }else if(m_flag == 2){
            cout<<"Error: out of range( array length "<<m_len<<", access index "<<m_index<<" )"<<endl;
        }else{
            cout<<"Unknown exception."<<endl;
        }
    }
    
    //实现动态数组
    class Array{
    public:
        Array();
        ~Array(){ free(m_p); };
    public:
        int operator[](int i) const;  //获取数组元素
        int push(int ele);  //在末尾插入数组元素
        int pop();  //在末尾删除数组元素
        int length() const{ return m_len; };  //获取数组长度
    private:
        int m_len;  //数组长度
        int m_capacity;  //当前的内存能容纳多少个元素
        int *m_p;  //内存指针
    private:
        static const int m_stepSize = 50;  //每次扩容的步长
    };
    
    Array::Array(){
        m_p = (int*)malloc( sizeof(int) * m_stepSize );
        m_capacity = m_stepSize;
        m_len = 0;
    }
    int Array::operator[](int index) const {
        if( index<0 || index>=m_len ){  //判断是否越界
            throw OutOfRange(m_len, index);  //抛出异常(创建一个匿名对象)
        }
    
        return *(m_p + index);
    }
    int Array::push(int ele){
        if(m_len >= m_capacity){  //如果容量不足就扩容
            m_capacity += m_stepSize;
            m_p = (int*)realloc( m_p, sizeof(int) * m_capacity );  //扩容
        }
    
        *(m_p + m_len) = ele;
        m_len++;
        return m_len-1;
    }
    int Array::pop(){
        if(m_len == 0){
             throw OutOfRange();  //抛出异常(创建一个匿名对象)
        }
    
        m_len--;
        return *(m_p + m_len);
    }
    
    //打印数组元素
    void printArray(Array &arr){
        int len = arr.length();
    
        //判断数组是否为空
        if(len == 0){
            cout<<"Empty array! No elements to print."<<endl;
            return;
        }
    
        for(int i=0; i<len; i++){
            if(i == len-1){
                cout<<arr[i]<<endl;
            }else{
                cout<<arr[i]<<", ";
            }
        }
    }
    
    int main(){
        Array nums;
        //向数组中添加十个元素
        for(int i=0; i<10; i++){
            nums.push(i);
        }
        printArray(nums);
    
        //尝试访问第20个元素
        try{
            cout<<nums[20]<<endl;
        }catch(OutOfRange &e){
            e.what();
        }
    
        //尝试弹出20个元素
        try{
            for(int i=0; i<20; i++){
                nums.pop();
            }
        }catch(OutOfRange &e){
            e.what();
        }
    
        printArray(nums);
    
        return 0;
    }
    

    运行结果:

    0, 1, 2, 3, 4, 5, 6, 7, 8, 9
    Error: out of range( array length 10, access index 20 )
    Error: empty array, no elements to pop.
    Empty array! No elements to print.
    

    Array 类实现了动态数组,它的主要思路是:在创建对象时预先分配出一定长度的内存(通过 malloc() 分配),内存不够用时就再扩展内存(通过 realloc() 重新分配)。Array 数组只能在尾部一个一个地插入(通过 push() 插入)或删除(通过 pop() 删除)元素。

    我们通过重载过的[ ]运算符来访问数组元素,如果下标过小或过大,就会抛出异常(第53行代码);在抛出异常的同时,我们还记录了当前数组的长度和要访问的下标。

    在使用 pop() 删除数组元素时,如果当前数组为空,也会抛出错误。

    throw 用作异常规范

    throw 关键字除了可以用在函数体中抛出异常,还可以用在函数头和函数体之间,指明当前函数能够抛出的异常类型,这称为异常规范(Exception specification)。

    double func (char param) throw (int);
    

    这条语句声明了一个名为 func 的函数,它的返回值类型为 double,有一个 char 类型的参数,并且只能抛出 int 类型的异常。如果抛出其他类型的异常,try 将无法捕获,只能终止程序。

    如果函数会抛出多种类型的异常,那么可以用逗号隔开:

    double func (char param) throw (int, char, exception);
    

    如果函数不会抛出任何异常,那么( )中什么也不写:

    double func (char param) throw ();
    

    如此,func() 函数就不能抛出任何类型的异常了,即使抛出了,try 也检测不到。

    1 虚函数中的异常规范
    C++ 规定,派生类虚函数的异常规范必须与基类虚函数的异常规范一样严格,或者更严格。只有这样,当通过基类指针(或者引用)调用派生类虚函数时,才能保证不违背基类成员函数的异常规范。请看下面的例子:

    class Base{
    public:
        virtual int fun1(int) throw();
        virtual int fun2(int) throw(int);
        virtual string fun3() throw(int, string);
    };
    class Derived:public Base{
    public:
        int fun1(int) throw(int);   //错!异常规范不如 throw() 严格
        int fun2(int) throw(int);   //对!有相同的异常规范
        string fun3() throw(string);  //对!异常规范比 throw(int,string) 更严格
    }
    

    2 异常规范与函数定义和函数声明
    C++ 规定,异常规范在函数声明和函数定义中必须同时指明,并且要严格保持一致,不能更加严格或者更加宽松。

    请看下面的几组函数:

    //错!定义中有异常规范,声明中没有
    void func1();
    void func1() throw(int) { }
    
    //错!定义和声明中的异常规范不一致
    void func2() throw(int);
    void func2() throw(int, bool) { }
    
    //对!定义和声明中的异常规范严格一致
    void func3() throw(float, char*);
    void func3() throw(float, char*) { }
    

    抛弃异常规范

    异常规范的初衷是好的,它希望让程序员看到函数的定义或声明后,立马就知道该函数会抛出什么类型的异常,这样程序员就可以使用 try-catch 来捕获了。如果没有异常规范,程序员必须阅读函数源码才能知道函数会抛出什么异常。

    不过这有时候也不容易做到。例如,func_outer() 函数可能不会引发异常,但它调用了另外一个函数 func_inner(),这个函数可能会引发异常。再如,您编写的函数调用了老式的库函数,此时不会引发异常,但是库更新以后这个函数却引发了异常。总之,异常规范的初衷实现起来有点困难,所以大家达成的一致意见是,最好不要使用异常规范。

    异常规范是 C++98 新增的一项功能,但是后来的 C++11 已经将它抛弃了,不再建议使用。

    另外,各个编译器对异常规范的支持也不一样,请看下面的代码:

    #include <iostream>
    #include <string>
    #include <exception>
    using namespace std;
    
    void func()throw(char*, exception){
        throw 100;
        cout<<"[1]This statement will not be executed."<<endl;
    }
    
    int main(){
        try{
            func();
        }catch(int){
            cout<<"Exception type: int"<<endl;
        }
    
        return 0;
    }
    

    在 GCC 下,这段代码运行到第 7 行时程序会崩溃。虽然 func() 函数中发生了异常,但是由于 throw 限制了函数只能抛出 char*、exception 类型的异常,所以 try-catch 将捕获不到异常,只能交给系统处理,终止程序。

    在 Visual C++ 下,输出结果为Exception type: int,这说明异常被成功捕获了。在 Visual C++ 中使用异常规范虽然没有语法错误,但是也没有任何效果,Visual C++ 会直接忽略异常规范的限制,函数可以抛出任何类型的异常。

    展开全文
  • C++ throw的坑

    千次阅读 2018-07-26 15:22:17
    由于平时使用的少。...底层throw异常信息而上层没有去cath该异常信息导致程序直接崩溃。所以有throw的地方就一定的有地方去接该异常信息。 下面是一个不错的博客https://www.cnblogs.com/QG-whz/p/5136883.html...

    由于平时使用的少。今天遇到一个恶心的问题。底层throw异常信息而上层没有去cath该异常信息导致程序直接崩溃。所以有throw的地方就一定的有地方去接该异常信息。

    下面是一个不错的博客https://www.cnblogs.com/QG-whz/p/5136883.html

    展开全文
  • c++ throw 抛出异常

    2019-06-26 04:30:01
    抛出异常(也称为抛弃异常)即检测是否产生异常,在C++中,其采用throw语句来实现,如果检测到产生异常,则抛出异常。该语句的格式为:throw 表达式; 如果在try语句块的程序段中(包括在其中调用的函数)发现了异常...
     抛出异常(也称为抛弃异常)即检测是否产生异常,在C++中,其采用throw语句来实现,如果检测到产生异常,则抛出异常。该语句的格式为:
    throw 表达式;
        如果在try语句块的程序段中(包括在其中调用的函数)发现了异常,且抛弃了该异常,则这个异常就可以被try语句块后的某个catch语句所捕获并处理,捕获和处理的条件是被抛弃的异常的类型与catch语句的异常类型相匹配。由于C++使用数据类型来区分不同的异常,因此在判断异常时,throw语句中的表达式的值就没有实际意义,而表达式的类型就特别重要。
    【范例20-2】处理除数为0的异常。该范例将上述除数为0的异常可以用try/catch语句来捕获异常,并使用throw语句来抛出异常,从而实现异常处理,实现代码如代码清单20-2所示。
    代码清单20-2
    1    #include<iostream.h>                                 //包含头文件
    2    #include<stdlib.h>
    3    double fuc(double x, double y)                        //定义函数
    4    {
    5        if(y==0)
    6        {
    7            throw y;                                    //除数为0,抛出异常
    8        }
    9        return x/y;                                    //否则返回两个数的商
    10    }
    11    void main()
    12    {
    13        double res;
    14        try                                            //定义异常
    15        {
    16            res=fuc(2,3);
    17            cout<<"The result of x/y is : "<<res<<endl;
    18            res=fuc(4,0);                                //出现异常
    19        }
    20        catch(double)                                    //捕获并处理异常
    21        {
    22            cerr<<"error of dividing zero.\n";
    23            exit(1);                                    //异常退出程序
    24        }
    25    }
    【运行结果】在Visual C++中新建一个【C++ Source File】文件,输入上述的代码,编译无误后运行。
    【范例解析】上述代码中,在主函数main()的第14~19行中使用了try语句定义异常,其中包含3条有可能出现异常的语句,它们为调用两个数相除的函数。在代码的第20~24行定义了异常处理,即捕获异常后执行该段代码中的语句。此外,在函数fuc()的代码5~8行通过throw语句抛出异常。

    转载于:https://www.cnblogs.com/yuhua4/archive/2009/10/15/1584095.html

    展开全文
  • C++ throw 代替 goto

    2018-10-23 20:55:20
    bool throw_x = true; int i,j,k; try{ for(i=0;i&amp;amp;lt;10;i++){ for(j=0;j&amp;amp;lt;10;j++){ for(k=0;k&amp;amp;lt;10;k++){ ...

    第一次看到可以这样写,涨见识了。

    int main()
    {
    	bool throw_x = true;
    	int i,j,k;
    	try{
    	    for(i=0;i<10;i++){
    	        for(j=0;j<10;j++){
    	            for(k=0;k<10;k++){
    	                if(i==1 && j==2 && k==6){
    	                    throw throw_x;
    	                }
    	            }
    	        }
    	    }
    	}catch(...){
    	    cout<<"i="<<i<<",j="<<j<<",k="<<k<<endl;
    	}
    }
    

    我一直认为合适的地方使用goto是个不错的想法,比如多重循环跳出。
    注意不要方法中使用多个goto,注意goto lable之间变量的定义。
    当然,有很多方法可以替代goto,比如增加判断,但是必然导致不良的可读性。
    goto只是一个工具,用好他是程序员的职责,不要片面完全否认goto,存在即为合理。(linux源码都有很多goto)。)

    另外一个goto替代:

    do{
    	if(..)
    	break;
    }while(0);//while(false) while( __LINE__ == -1)
    
    展开全文
  • c++ throw try catch

    2016-11-26 15:50:19
    #include using namespace std; double fuc(double x, double y) //定义函数 ... //throw y; //除数为0,抛出异常 throw exception(); } return x/y; //否则返回两个数的商 } void main() {
  • C++ Throw Try catch

    2017-03-28 17:35:53
    要防止因为异常产生的内存泄漏,可以使用智能指针,也可以用 ...try,catch,throw: try包含你要防护的代码 ,称为防护块. 防护块如果出现异常,会自动生成异常对象并抛出. catch捕捉特定的异常,并在其中进行适当处理. thr
  • c++throw类型

    千次阅读 2012-08-13 02:29:21
    1 #include //包含头文件 2 #include 3 double fuc(double x, double y) //定义函数 4 { 5 if(y==0) 6 { 7 throw y;
  • C++ 中,我们使用 throw 关键字来显式地抛出异常,它的用法为: throw exceptionData; exceptionData 是“异常数据”的意思,它可以包含任意的信息,完全有程序员决定。exceptionData 可以是 int、float、bool
  • throw()关键词相信大家在很多C++教程或者代码中看到过,这个博客以一Stackoverflow上的问题开始:应该在C++中使用throw()关键词吗? 回答是:不应该 理由主要是各个编译器并没有一个统一的标准去处理这个关键词...
  • c++ throw() 解析

    千次阅读 2015-04-02 17:44:22
    最近在看 poco c++ 一个非常好的 poco c++ 框架。在看的时候发现一个语句不是很理解。 const char* Exception::what() const throw() 所有百度了一下。 记录如下: 它是函数提供者和使用者的一种约定,即提供者...
  • 原文:异常机制(throw、try、catch) 概念:异常处理是一种允许两个独立开发的程序组件在程序执行时遇到不正常的情况相互通信的工具 异常检测和异常处理的方式 throw表达式:程序遇到了错误或者无法处理的...
  • 深入 C++ throw

    2009-10-19 16:09:08
    深入throw:(i)、程序接受到throw语句后就会自动调用析构器,把该域(try后的括号内)对象clean up,然后再进入catch语句(如果在循环体中就退出循环)。这种机制会引起一些致命的错误,比如,当“类”有指针成员...
  • c++ throw异常(学习)

    2019-06-08 16:42:00
     throw 1;  }  out_file = fopen(dest_file, "wb");  if (out_file == NULL)  {  throw 2;  }  char rec[1024];  size_t bytes_in, bytes_out;  while ((bytes_in = fread(rec, 1, 1024, in_file))>0)...
  • 首先说明try catch throwc++异常处理机制。 throw放在方法后面,说明该方法是否抛出异常,是什么类型异常。 例子如下: class B { public: void fun() throw() { throw string("ex"); } void fun1() ...
  • C++ throw:抛出自己的异常

    万次阅读 2016-07-24 02:08:13
    throwC++中的关键字,用来抛出异常。如果不使用 throw 关键字,try 就什么也捕获不到;上节提到的 at() 函数在内部也使用了 throw 关键字来抛出异常。 throw 既可以用在标准库中,也可以用在自定义的函数中,...
  •  the implied restriction on the kind of classes that can be used to create exception objects, the throw exception in the iStack member function push() is in error if  the class pushOnFull does ...
  • 最近写代码发现一个抛std::string 的异常,问题如下 #pragma once ...TestThrow.exe 中的 0x7512a9f2 处最可能的异常: Microsoft C++ 异常: 内存位置 0x00effa18 处的 MyException。 哪位大神能解决一下呢
  • 如果定义了 throw() 表示函数不抛出异常,这时候如果还是抛出,会导致运行时错误。 #include &lt;iostream&gt; #include &lt;exception&gt; #include &lt;stack&gt; using namespace std...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,590
精华内容 1,036
关键字:

c++throw

c++ 订阅