把函數返回值轉爲異常處理機制

我們這裏要使用的是#include <stdexcept>,可以參考官方文檔
先舉一個例子,比如調用recv的函數返回值處理:

int ret = recv(fd...);
if (ret > 0){}
if (ret == 0){}
if (ret == -1)
{
    //EAGAIN/EWOULDBLOCK提示你的應用程序現在沒有數據可讀請稍後再試
    if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
    {
        break;
    }
    //EINTR指操作被中斷喚醒,需要重新讀
    else if (errno == EINTR)
    {
        continue;
    }
    //異常斷開情況
    else
    {
        close(fd);
        break;
    }
}

這裏僞代碼描述,具體處理方法可以參考我的文章epoll的ET和LT模式下,accept,recv,send寫法
重點我們關注的是ret == -1發生錯誤的情況,其中我們需要處理EAGAIN,EWOULDBLOCK,EINTR,其它錯誤這些情況,那麼首先這些返回值程序員可以不處理,或者說忘了處理,忽略了,但是我們轉爲返回異常,那麼就必須處理了,這樣的封裝有利於程序的健壯性;其次整型返回值沒有任何語義信息,而異常卻包含語義信息,有時你從類名就能夠體現出來。
現在我們對這幾個錯誤進行封裝:

class socket_again: public std::runtime_error
{
    socket_again(const std::string& s):std::runtime_error(s)
    {
    }
};

class socket_intr: public std::runtime_error
{
    socket_intr(const std::string& s):std::runtime_error(s)
    {
    }
};

class socket_error: public std::runtime_error
{
    socket_error(const std::string& s):std::runtime_error(s)
    {
    }
};

現在用封裝的異常來替換上面錯誤值的處理邏輯:

int my_recv(fd...)
{
    int ret = recv(fd...);
    if (ret == -1)
    {
        //EAGAIN/EWOULDBLOCK提示你的應用程序現在沒有數據可讀請稍後再試
        if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
        {
            throw socket_again(strerror(errno));
        }
        //EINTR指操作被中斷喚醒,需要重新讀
        else if (errno == EINTR)
        {
            throw socket_intr (strerror(errno));
        }
        //異常斷開情況
        else
        {
            throw socket_error(strerror(errno));
        }
    }
    return ret;
}

然後再調用my_recv完成所有的邏輯:

try 
{
    int ret = my_recv(fd...);
    if (ret > 0){}
    if (ret == 0){}
}
catch(socket_again& e)
{

}
catch(socket_intr& e)
{

}
catch(socket_error& e)
{

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章