2017-02-06 189 views
0

我正在從Windows/Linux控制檯取得輸入,以便用戶類型的密碼在幾乎所有Linux操作系統中都保持隱藏狀態。 我應該如何優雅地處理下面的代碼片段拋出的異常?異常處理C++

#ifdef _WIN32 
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); 
DWORD mode = 0; 
GetConsoleMode(hStdin, &mode); 
SetConsoleMode(hStdin, mode & (~ENABLE_ECHO_INPUT)); 

std::string sTempPass; 
getline(cin, sTempPass); 
SetConsoleMode(hStdin, mode); 

#elif __linux__ 
termios oldt; 
tcgetattr(STDIN_FILENO, &oldt); 
termios newt = oldt; 
newt.c_lflag &= ~ECHO; 
tcsetattr(STDIN_FILENO, TCSANOW, &newt); 

std::string sTempPass; 
getline(cin, sTempPass); 
tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 

,什麼是可能的方案上面的代碼可以拋出不同類型的異常,是有做到這一點其他任何​​平臺獨立的方式?

+0

您發佈的代碼不會拋出任何異常。 –

+1

@ el.pescado:有一個'getline(cin,sTempPass)''調用。至少這可能會引起'std :: bad_alloc'異常,因爲調整了輸出字符串緩衝區的大小。代碼*可以拋出異常。 – IInspectable

+0

@Inspectable你是對的。 –

回答

1

異常情況下所需的回滾操作通常通過在C++中運行析構函數來實現。你的情況,你可以創建一個存儲當前狀態的類,並且在它的析構函數恢復它:

struct ConsoleMode { 
    DWORD mode; 
    HANDLE handle; 
    ConsoleMode(const HANDLE h) : handle(h) { 
     ::GetConsoleMode(handle, &mode); 
    } 
    ~ConsoleMode() { 
     ::SetConsoleMode(handle, mode); 
    } 
} 

調用代碼,然後簡單地構造一個具有自動存儲時間的對象,並留下清理自動堆棧展開:

HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); 
{ 
    ConsoleMode savedState(hStdin); 
    ::SetConsoleMode(hStdin, savedState.mode & (~ENABLE_ECHO_INPUT)); 

    std::string sTempPass; 
    getline(cin, sTempPass); 

    // savedState goes out of scope and runs its destructor to restore state. 
    // The destructor runs as part of stack unwinding in case of an exception as well. 
} 

Linux實現類似,各自的系統調用和成員適當調整。

+0

可以處理hStdin = GetStdHandle(STD_INPUT_HANDLE);如果Handle沒有被返回,拋出異常? @Ilnspectable –

+0

@Milind:Windows API作爲C接口公開。錯誤僅通過返回值報告。在這種情況下,如果[GetStdHandle](https://msdn.microsoft.com/en-us/library/windows/desktop/ms683231.aspx)失敗,它將返回'INVALID_HANDLE_VALUE'(或'NULL')。即使它確實拋出異常,也無所謂,因爲調用是在改變全局狀態之前進行的。 (Y) – IInspectable

+0

使感覺,感謝(Y) –