欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++ throw關(guān)鍵字實(shí)現(xiàn)拋出異常和異常規(guī)范

 更新時(shí)間:2021年08月09日 09:30:51   投稿:zx  
本文主要介紹了C++ throw關(guān)鍵字實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

在《C++異常入門》一節(jié)中,我們講到了 C++ 異常處理的流程,具體為:

拋出(Throw)--> 檢測(cè)(Try) --> 捕獲(Catch)

異常必須顯式地拋出,才能被檢測(cè)和捕獲到;如果沒有顯式的拋出,即使有異常也檢測(cè)不到。

在 C++ 中,我們使用 throw 關(guān)鍵字來顯式地拋出異常,它的用法為:

throw exceptionData;

exceptionData 是“異常數(shù)據(jù)”的意思,它可以包含任意的信息,完全有程序員決定。exceptionData 可以是 int、float、bool 等基本類型,也可以是指針、數(shù)組、字符串、結(jié)構(gòu)體、類等聚合類型,請(qǐng)看下面的例子:

char str[] = "http://c.biancheng.net";
char *pstr = str;
class Base{};
Base obj;
throw 100;  //int 類型
throw str;  //數(shù)組類型
throw pstr;  //指針類型
throw obj;  //對(duì)象類型

一個(gè)動(dòng)態(tài)數(shù)組的例子

C/C++ 規(guī)定,數(shù)組一旦定義后,它的長(zhǎng)度就不能改變了;換句話說,數(shù)組容量不能動(dòng)態(tài)地增大或者減小。這樣的數(shù)組稱為靜態(tài)數(shù)組(Static array)。靜態(tài)數(shù)組有時(shí)候會(huì)給編碼代碼不便,我們可以通過自定義的 Array 類來實(shí)現(xiàn)動(dòng)態(tài)數(shù)組(Dynamic array)。所謂動(dòng)態(tài)數(shù)組,是指數(shù)組容量能夠在使用的過程中隨時(shí)增大或減小。

下面這段代碼雖然有點(diǎn)長(zhǎng),但它是一個(gè)典型的使用異常的場(chǎng)景,請(qǐng)大家耐心閱讀。

#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;  //獲取具體的錯(cuò)誤信息
private:
    int m_flag;  //不同的flag表示不同的錯(cuò)誤
    int m_len;  //當(dāng)前數(shù)組的長(zhǎng)度
    int m_index;  //當(dāng)前使用的數(shù)組下標(biāo)
};
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;
    }
}
//實(shí)現(xiàn)動(dòng)態(tài)數(shù)組
class Array{
public:
    Array();
    ~Array(){ free(m_p); };
public:
    int operator[](int i) const;  //獲取數(shù)組元素
    int push(int ele);  //在末尾插入數(shù)組元素
    int pop();  //在末尾刪除數(shù)組元素
    int length() const{ return m_len; };  //獲取數(shù)組長(zhǎng)度
private:
    int m_len;  //數(shù)組長(zhǎng)度
    int m_capacity;  //當(dāng)前的內(nèi)存能容納多少個(gè)元素
    int *m_p;  //內(nèi)存指針
private:
    static const int m_stepSize = 50;  //每次擴(kuò)容的步長(zhǎng)
};
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);  //拋出異常(創(chuàng)建一個(gè)匿名對(duì)象)
    }
    return *(m_p + index);
}
int Array::push(int ele){
    if(m_len >= m_capacity){  //如果容量不足就擴(kuò)容
        m_capacity += m_stepSize;
        m_p = (int*)realloc( m_p, sizeof(int) * m_capacity );  //擴(kuò)容
    }
    *(m_p + m_len) = ele;
    m_len++;
    return m_len-1;
}
int Array::pop(){
    if(m_len == 0){
         throw OutOfRange();  //拋出異常(創(chuàng)建一個(gè)匿名對(duì)象)
    }
    m_len--;
    return *(m_p + m_len);
}
//打印數(shù)組元素
void printArray(Array &arr){
    int len = arr.length();
    //判斷數(shù)組是否為空
    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;
    //向數(shù)組中添加十個(gè)元素
    for(int i=0; i<10; i++){
        nums.push(i);
    }
    printArray(nums);
    //嘗試訪問第20個(gè)元素
    try{
        cout<<nums[20]<<endl;
    }catch(OutOfRange &e){
        e.what();
    }
    //嘗試彈出20個(gè)元素
    try{
        for(int i=0; i<20; i++){
            nums.pop();
        }
    }catch(OutOfRange &e){
        e.what();
    }
    printArray(nums);
    return 0;
}

運(yùn)行結(jié)果:
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 類實(shí)現(xiàn)了動(dòng)態(tài)數(shù)組,它的主要思路是:在創(chuàng)建對(duì)象時(shí)預(yù)先分配出一定長(zhǎng)度的內(nèi)存(通過 malloc() 分配),內(nèi)存不夠用時(shí)就再擴(kuò)展內(nèi)存(通過 realloc() 重新分配)。Array 數(shù)組只能在尾部一個(gè)一個(gè)地插入(通過 push() 插入)或刪除(通過 pop() 刪除)元素。

我們通過重載過的[ ]運(yùn)算符來訪問數(shù)組元素,如果下標(biāo)過小或過大,就會(huì)拋出異常(第53行代碼);在拋出異常的同時(shí),我們還記錄了當(dāng)前數(shù)組的長(zhǎng)度和要訪問的下標(biāo)。

在使用 pop() 刪除數(shù)組元素時(shí),如果當(dāng)前數(shù)組為空,也會(huì)拋出錯(cuò)誤。

throw 用作異常規(guī)范

throw 關(guān)鍵字除了可以用在函數(shù)體中拋出異常,還可以用在函數(shù)頭和函數(shù)體之間,指明當(dāng)前函數(shù)能夠拋出的異常類型,這稱為異常規(guī)范(Exception specification),有些教程也稱為異常指示符或異常列表。請(qǐng)看下面的例子:
double func (char param) throw (int);

這條語句聲明了一個(gè)名為 func 的函數(shù),它的返回值類型為 double,有一個(gè) char 類型的參數(shù),并且只能拋出 int 類型的異常。如果拋出其他類型的異常,try 將無法捕獲,只能終止程序。

如果函數(shù)會(huì)拋出多種類型的異常,那么可以用逗號(hào)隔開:

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

如果函數(shù)不會(huì)拋出任何異常,那么( )中什么也不寫:

double func (char param) throw ();

如此,func() 函數(shù)就不能拋出任何類型的異常了,即使拋出了,try 也檢測(cè)不到。

1) 虛函數(shù)中的異常規(guī)范

C++ 規(guī)定,派生類虛函數(shù)的異常規(guī)范必須與基類虛函數(shù)的異常規(guī)范一樣嚴(yán)格,或者更嚴(yán)格。只有這樣,當(dāng)通過基類指針(或者引用)調(diào)用派生類虛函數(shù)時(shí),才能保證不違背基類成員函數(shù)的異常規(guī)范。請(qǐng)看下面的例子:

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);   //錯(cuò)!異常規(guī)范不如 throw() 嚴(yán)格
    int fun2(int) throw(int);   //對(duì)!有相同的異常規(guī)范
    string fun3() throw(string);  //對(duì)!異常規(guī)范比 throw(int,string) 更嚴(yán)格
}

2) 異常規(guī)范與函數(shù)定義和函數(shù)聲明

C++ 規(guī)定,異常規(guī)范在函數(shù)聲明和函數(shù)定義中必須同時(shí)指明,并且要嚴(yán)格保持一致,不能更加嚴(yán)格或者更加寬松。

請(qǐng)看下面的幾組函數(shù):

//錯(cuò)!定義中有異常規(guī)范,聲明中沒有
void func1();
void func1() throw(int) { }
//錯(cuò)!定義和聲明中的異常規(guī)范不一致
void func2() throw(int);
void func2() throw(int, bool) { }
//對(duì)!定義和聲明中的異常規(guī)范嚴(yán)格一致
void func3() throw(float, char*);
void func3() throw(float, char*) { }

請(qǐng)拋棄異常規(guī)范,不要再使用它

異常規(guī)范的初衷是好的,它希望讓程序員看到函數(shù)的定義或聲明后,立馬就知道該函數(shù)會(huì)拋出什么類型的異常,這樣程序員就可以使用 try-catch 來捕獲了。如果沒有異常規(guī)范,程序員必須閱讀函數(shù)源碼才能知道函數(shù)會(huì)拋出什么異常。

不過這有時(shí)候也不容易做到。例如,func_outer() 函數(shù)可能不會(huì)引發(fā)異常,但它調(diào)用了另外一個(gè)函數(shù) func_inner(),這個(gè)函數(shù)可能會(huì)引發(fā)異常。再如,您編寫的函數(shù)調(diào)用了老式的庫函數(shù),此時(shí)不會(huì)引發(fā)異常,但是庫更新以后這個(gè)函數(shù)卻引發(fā)了異常??傊?,異常規(guī)范的初衷實(shí)現(xiàn)起來有點(diǎn)困難,所以大家達(dá)成的一致意見是,最好不要使用異常規(guī)范。

異常規(guī)范是 C++98 新增的一項(xiàng)功能,但是后來的 C++11 已經(jīng)將它拋棄了,不再建議使用。

另外,各個(gè)編譯器對(duì)異常規(guī)范的支持也不一樣,請(qǐng)看下面的代碼:

#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 下,這段代碼運(yùn)行到第 7 行時(shí)程序會(huì)崩潰。雖然 func() 函數(shù)中發(fā)生了異常,但是由于 throw 限制了函數(shù)只能拋出 char*、exception 類型的異常,所以 try-catch 將捕獲不到異常,只能交給系統(tǒng)處理,終止程序。

在 Visual C++ 下,輸出結(jié)果為Exception type: int,這說明異常被成功捕獲了。在 Visual C++ 中使用異常規(guī)范雖然沒有語法錯(cuò)誤,但是也沒有任何效果,Visual C++ 會(huì)直接忽略異常規(guī)范的限制,函數(shù)可以拋出任何類型的異常。

到此這篇關(guān)于C++ throw關(guān)鍵字實(shí)現(xiàn)拋出異常和異常規(guī)范的文章就介紹到這了,更多相關(guān)C++ throw關(guān)鍵字 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言利用EasyX實(shí)現(xiàn)繪制足球圖案

    C語言利用EasyX實(shí)現(xiàn)繪制足球圖案

    這篇文章主要為大家詳細(xì)介紹了C語言如何利用EasyX繪圖庫實(shí)現(xiàn)繪制一個(gè)簡(jiǎn)單的足球圖案,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2022-11-11
  • C++抽獎(jiǎng)程序?qū)崿F(xiàn)方法

    C++抽獎(jiǎng)程序?qū)崿F(xiàn)方法

    這篇文章主要介紹了C++抽獎(jiǎng)程序?qū)崿F(xiàn)方法,實(shí)例分析了C++隨機(jī)數(shù)的生成技巧與抽獎(jiǎng)程序的實(shí)現(xiàn)方法,需要的朋友可以參考下
    2015-07-07
  • C語言初識(shí)變量常量字符串轉(zhuǎn)義符及注釋方式簡(jiǎn)介

    C語言初識(shí)變量常量字符串轉(zhuǎn)義符及注釋方式簡(jiǎn)介

    最強(qiáng)的C語言筆記,此處對(duì)于C語言的基礎(chǔ)部分做一個(gè)簡(jiǎn)要的介紹,作者實(shí)屬初學(xué),寫博客也是作者學(xué)習(xí)的一個(gè)過程,若文中內(nèi)容有理解不到位或者有不當(dāng)之處,還請(qǐng)朋友們不吝指正
    2021-11-11
  • 詳解C語言內(nèi)核中的鏈表與結(jié)構(gòu)體

    詳解C語言內(nèi)核中的鏈表與結(jié)構(gòu)體

    Windows內(nèi)核中是無法使用vector容器等數(shù)據(jù)結(jié)構(gòu)的,當(dāng)我們需要保存一個(gè)結(jié)構(gòu)體數(shù)組時(shí),就需要使用內(nèi)核中提供的專用鏈表結(jié)構(gòu)。本文分享了幾個(gè)內(nèi)核中使用鏈表存儲(chǔ)多個(gè)結(jié)構(gòu)體的通用案例,希望對(duì)你有所幫助
    2022-09-09
  • C語言簡(jiǎn)明講解類型轉(zhuǎn)換的使用與作用

    C語言簡(jiǎn)明講解類型轉(zhuǎn)換的使用與作用

    類型轉(zhuǎn)換(type?cast),是高級(jí)語言的一個(gè)基本語法。它被實(shí)現(xiàn)為一個(gè)特殊的運(yùn)算符,以小括號(hào)內(nèi)加上類型名來表示,接下來讓我們一起來詳細(xì)了解
    2022-04-04
  • C++實(shí)現(xiàn)八個(gè)常用的排序算法 插入排序、冒泡排序、選擇排序、希爾排序等

    C++實(shí)現(xiàn)八個(gè)常用的排序算法 插入排序、冒泡排序、選擇排序、希爾排序等

    這篇文章主要介紹了C++如何實(shí)現(xiàn)八個(gè)常用的排序算法:插入排序、冒泡排序、選擇排序、希爾排序 、快速排序、歸并排序、堆排序和LST基數(shù)排序,需要的朋友可以參考下
    2015-07-07
  • C++基本用法實(shí)踐之模板詳解

    C++基本用法實(shí)踐之模板詳解

    C++的模板是泛型編程思想的一種實(shí)現(xiàn),模板不光支持函數(shù)模板,還有類模板等,本文主要來和大家聊聊C++中模板的相關(guān)用法,需要的可以參考一下
    2023-07-07
  • C++中putchar與getchar函數(shù)的細(xì)節(jié)及運(yùn)用

    C++中putchar與getchar函數(shù)的細(xì)節(jié)及運(yùn)用

    C語言提供putchar函數(shù),用于給終端輸出一個(gè)字符;getchar函數(shù),可以從終端接收用戶輸入的一個(gè)字符,本文給大家分享C++中putchar與getchar函數(shù)的細(xì)節(jié)及運(yùn)用,感興趣的朋友跟隨小編一起看看吧
    2021-07-07
  • C++詳細(xì)講解print緩沖區(qū)的刷新

    C++詳細(xì)講解print緩沖區(qū)的刷新

    這篇文章主要介紹了print緩沖區(qū)刷新問題,實(shí)現(xiàn)代碼簡(jiǎn)單易懂,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,需要的朋友可以參考下
    2022-05-05
  • C語言編程中從密碼文件獲取數(shù)據(jù)的函數(shù)總結(jié)

    C語言編程中從密碼文件獲取數(shù)據(jù)的函數(shù)總結(jié)

    這篇文章主要介紹了C語言編程中從密碼文件獲取數(shù)據(jù)的函數(shù)總結(jié),包括getpw()函數(shù)和getpwnam()函數(shù)以及getpwuid()函數(shù),需要的朋友可以參考下
    2015-08-08

最新評(píng)論