2012-08-05 67 views
1

我正在創建一個庫。我想製作一個固定長度的字符串類。投擲異常與返回結果代碼

#include <string> 
#include <iostream> 

#define OK 0 
#define TOO_LONG 1 
#define UNALLOWED_CHARACTERS 2 

struct MyString { 
    MyString(int l) 
     : m_length(l) { } 
    struct exception { 
     exception(int t, MyString *p) 
      : type(t), ptr(p) { } 
     int type; 
     MyString *ptr; 
    }; 
    int set(const std::string& name); 
    void set2(const std::string& name) throw(exception); 

    std::string m_str; 
    int m_length; 
}; 

int MyString::set(const std::string& s) 
{ 
    if(s.size() > 64) { 
     return TOO_LONG; 
    } else if(s.find('~') != std::string::npos) { 
     return UNALLOWED_CHARACTERS; 
    } else { 
     m_str = s; 
     return OK; 
    } 
} 

void MyString::set2(const std::string& s) throw(exception) 
{ 
    if(s.size() > m_length) { 
     throw exception(TOO_LONG, this); 
    } else if(s.find('~') != std::string::npos) { 
     throw exception(UNALLOWED_CHARACTERS, this); 
    } else { 
     m_str = s; 
    } 
} 

int main() 
{ 
    using namespace std; 
    //OPTION 1 
    { 
     MyString s1(10); 
     MyString s2(10); 
     int code; 

     code = s1.set("abcdefghijX"); 
     switch(code) { 
     case TOO_LONG: 
      //handle <-- 
      break; 
     case UNALLOWED_CHARACTERS: 
      //handle 
      break; 
     default: 
      //ok! 
      break; 
     } 

     code = s2.set("abcdefghi~"); 
     switch(code) { 
     case TOO_LONG: 
      //handle 
      break; 
     case UNALLOWED_CHARACTERS: 
      //handle <-- 
      break; 
     default: 
      //ok! 
      break; 
     } 
    } 

    //OPTION 2 
    { 
     MyString s1(10); 
     MyString s2(10); 
     try { 
      s1.set2("abcdefghijX"); 
      s2.set2("abcdefghi~"); 

     } catch(MyString::exception &e) { 
      cerr << "MyString::exception: "; 
      auto p = e.ptr; 
      if(p == &s1) cerr << "s1 "; 
      else if(p == &s2) cerr << "s2 "; 
      switch(e.type) { 
       case TOO_LONG: cerr << "too long"; break; 
       case UNALLOWED_CHARACTERS: cerr << "unallowed characters"; break; 
      } 
      cerr << endl; 
     } 

    } 
} 

我不知道我應該使用MyString :: set()的哪個版本。這種情況下的約定是什麼?爲了演示目的,我在本例中使用了STL。

+1

這是一個表面上很好的問題,但實際上會引起很多爭論。這是那些宗教問題之一。 – djechlin 2012-08-05 15:57:55

+1

另外,請勿使用投擲規格。我只能假設它們是在運行時檢查的白癡原因,並且會導致std :: unexpected並因此被破壞(如果被違反)(在調試/開發設置中有用,但不在生產環境中),這實際上是相反的你想要做什麼例外。 – djechlin 2012-08-05 16:00:06

+1

@djechlin好點。而且,異常規範在C++ 11中已棄用。 – juanchopanza 2012-08-05 16:39:00

回答

1

它是模仿的標準庫函數的行爲是一個好主意,除非一個有特定的理由。順便說一下,自tr1以來,STL有一個固定長度的字符串類內置。讓我們看看它的作用。唯一的示例實現我是得心應手的Visual C++ 2010

 

std::tr1::array<int,5> arry; 
arry[10] = 42; // Oopsie. There is no element 10. 
 

編譯和運行的「調試」版本,我得到一個斷言失敗。當編譯爲「發佈」的時候,這個攻擊性聲明悄悄地......沒有任何東西。它優化不存在。好吧,也許這並不總是人們想要的。忘記我所說的模仿STL,或者至少是微軟的實現。意識列車繼續...

我認爲這是公平的說,如果程序試圖設置超出範圍的單元格,這是程序中的邏輯錯誤。在關鍵任務軟件中,可能有一個好主意,讓代碼可以處理這樣的情況並從中恢復,同時儘可能確保它永遠不會發生。

所以答案是,拋出std :: out_of_range類型的異常。

所以那裏。

+0

好吧,我剛剛閱讀了一些關於標準例外的信息,它們適合我的需求。我只是認爲_std :: length_error_更精確一些,因爲我不能接受'mapObject.name ='這樣的語句,這個名字對於地圖名稱來說太長!「('name'是一個屬性)。 – cubuspl42 2012-08-10 14:59:20

1

通常在C++中,建議使用異常來指示在當前上下文中不可恢復的錯誤。但這取決於目的。您可能希望在沒有例外情況的嵌入式環境中編譯庫(爲了提高效率),那麼您必須使用返回代碼。

它很容易將使用返回碼的API包裝爲使用異常的API,但反之亦然。

編輯:

一些更多的理由爲什麼它可能是有意義的不使用異常處理:

異常處理通常帶來額外的信息被放置在調用棧+一些性能需要約try/catch塊建立和檢查這些信息的懲罰。

參見:performance of C++0x exceptions

+0

如果錯誤是「不可恢復的」,則不需要錯誤代碼或拋出異常。打電話給()並完成它。 – 2012-08-09 03:44:53

+0

嘗試塊是爲了「所有這些都必須完成,否則就是放鬆堆棧並讓我回到catch-block」。通常情況確實例外。然而,我記得在我所有幾十年的編程中,只有一個應用程序,當堆棧很深並且不再需要幀時,完成任務是正常的。不尋常的情況是跑完成(然後放棄失敗)。對於該功能,拋出(「成功」)是期望的結果,並且是正常的。 – 2012-08-09 03:56:19

+0

@JiveDadson我已經改變了一些措辭,我認爲這是更全面的,我的意思是'不可恢復的'。 – 2012-08-09 07:50:43