异常处理 C++

Posted

技术标签:

【中文标题】异常处理 C++【英文标题】:Exception Handling C++ 【发布时间】:2017-02-06 10:15:46 【问题描述】:

我从 Windows/Linux 控制台接收输入,以便用户键入的密码保持隐藏状态,因为它在几乎所有 Linux 操作系统中都会发生。 下面sn-p抛出的异常应该如何优雅的处理?

#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);

上面的 sn-p 可能抛出不同类型的异常的可能场景是什么?还有其他独立于平台的方法吗?

【问题讨论】:

您发布的代码不会抛出任何异常。 @el.pescado:有一个getline(cin, sTempPass); 调用。由于调整输出字符串缓冲区的大小,这至少会引发std::bad_alloc 异常。代码可以抛出异常。 @IInspectable 你是对的。 【参考方案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 实现是类似的,相应的系统调用和成员进行了适当调整。

【讨论】:

可以处理 hStdin = GetStdHandle(STD_INPUT_HANDLE);如果不返回句柄,则抛出异常? @Ilnspectable @Milind:Windows API 公开为 C 接口。错误仅通过返回值报告。在这种情况下,如果GetStdHandle 失败,则返回INVALID_HANDLE_VALUE(或NULL)。即使它确实抛出了异常也没关系,因为调用是在更改全局状态之前进行的。 有道理,谢谢 (Y)

以上是关于异常处理 C++的主要内容,如果未能解决你的问题,请参考以下文章

C++ 异常处理

C++异常处理的编程方法(阿愚,整整29集)

C++学习笔记13--异常处理

C++ 异常处理

C++异常处理

C++异常处理