2010-11-11 115 views
1

我遇到了一個令人討厭的問題,我寫了一個C++函數,其目的是驗證用戶輸入。該函數讀取用戶輸入,驗證它是否是數字,如果是,它是否在範圍[min,max]中。將字符串錯誤的類型轉換爲unsigned int

當我使用無符號類型調用模板函數(如size_t),並且輸入是負數時,會發生此問題。字符串流將字符串轉換爲類似於4294967291的字符串。我可以看到程序正在將數據轉換爲接近無符號數據類型的最大值(在numeric_limits標頭中定義)的值,但我的問題是爲什麼,因爲if語句應該停在sstream >> value

我的代碼:

template <class T> 
T getNumberInput(std::string prompt, T min, T max) { 
    std::string input; 
    T value; 

    while (true) { 
     try { 
      std::cout << prompt; 
      std::cin.clear(); 
      std::getline(std::cin, input); 
      std::stringstream sstream(input); 

      if (input.empty()) { 
       throw EmptyInput<std::string>(input); 
      } else if (sstream >> value && value >= min && value <= max) { 
       std::cout << std::endl; 
       return value; 
      } else { 
       throw InvalidInput<std::string>(input); 
      } 
     } catch (EmptyInput<std::string> & emptyInput) { 
      std::cout << "O campo não pode ser vazio!\n" << std::endl; 
     } catch (InvalidInput<std::string> & invalidInput){ 
      std::cout << "Tipo de dados inválido!\n" << std::endl; 
     } 
    } 
} 

謝謝您的時間!

+0

不要傳遞它一個無符號類型? – Mud 2010-11-11 04:38:38

回答

2

在C++算術涉及一個unsigned類型與Ñ值的比特,是保證將模2^Ñ。這意味着通過添加或減去2的合適倍數,將任何結果回捲到0到2的範圍內。這也是在C.

所以你需要檢查減號輸入,或添加一些其他檢查。

順便說一下,您的if>>&&對我的壞碼錶產生了一些影響。我永遠不會記得>>&&的運算符優先級。我想如果它編譯它一定是好的,但是,因爲>>不能取右值。檢查...好的,但我會用圓括號來說明這一點。

此外,在代碼結構上,將交互輸入與輸入檢查分開是一個好主意。例如,您可以在GUI程序中使用任何代碼,並使用編輯字段的輸入?不,不是因爲它是...

乾杯&心連心,

+1

感謝您的理論解釋。它幫助我理解這個問題。增加了減號檢查,它可以很好地工作:'if(input [0] ==' - '&& std :: numeric_limits :: min()== 0)'。關於壞碼,你完全正確,因此我也解決了這個問題:'if((sstream >> value)&&(value> = min)&&(value <= max))'。事實上,它更具可讀性,並且沒有任何疑問。 – 2010-11-11 05:11:33

+0

最後,至少在代碼結構上,我認爲解決方案將把函數分成兩部分,一部分用戶輸入,另一部分用於驗證。我只有一個懷疑。我應該將try和catch塊留在getter中,還是完全處理validator中的異常? – 2010-11-11 05:11:54

+0

@renatorodrigues:保留你擁有的函數的合約是很自然的,並且包括它對異常的迴應。我設想了更多的重構,比如將getline後面的代碼移動到第一個catch,並將其移動到一個單獨的函數中,該函數接受一個字符串併產生一個數字(或者在不能時拋出)。乾杯, – 2010-11-11 06:10:21

1

阿爾夫已經回答了這一點,但我有一對夫婦的其他的想法。 拉取從try塊中取出輸入的代碼。你沒有捕捉它可能拋出的任何異常,所以它也沒有傳達這個意圖。 try塊應該在if(input.empty())之前開始... 然後將try塊中的所有東西放到一個validate函數中。這清理了代碼。但是,對於在GUI中的使用,您希望創建一個只需獲取輸入而不進行驗證並顯示驗證功能的函數。然後用戶可以根據需要處理驗證異常。儘管在這種情況下,我並沒有看到使用異常而不是簡單的錯誤代碼進行驗證的好處。

希望這會有所幫助,

+0

嗯,它確實有幫助。謝謝! – 2010-11-11 12:19:06

相關問題