2017-02-06 241 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) –