【问题标题】:C++ handling unanticipated errorsC++ 处理意外错误
【发布时间】:2012-05-29 12:18:04
【问题描述】:

我需要为一个研究项目学习 C++ 基础知识,并且我正在尝试错误/异常处理。我确实成功地使用了throw 命令来预测可能发生的事件(例如除以零),但我不知道如何捕获意外异常。拿这个示例代码:

#include <iostream>
#include <exception>
#include <stdexcept>
using namespace std;

void arrayOutOfBound()
{
    int a[3] = {1, 2, 3};

    try
    {
        cout << "This should not display: " << a[5] << endl;
    }
    catch(runtime_error &e)
    /* catch(exception &e)     // also does not work  */
    {
        cout << "Error: " << e.what() << endl;
    }
}

int main()
{
    arrayOutOfBound();
}

我想我必须在某处使用throw 语句,但假设我真的不知道a[5] 不起作用(或者用户输入了这个索引并且我没有检查数组大小),那么如何我可以防止程序崩溃吗? (这发生在 Visual C++ Express 2010 调试器中)

注意:如果我先在块外执行try { int result = a[5]; },然后尝试在最后使用cout &lt;&lt; result,则程序无法编译。编译器试图帮助我,但我无法尝试异常处理。

【问题讨论】:

  • 重点不是真的知道a[5] 是否会成功,而是要为a[x] 的失败做好准备(以同样的方式)。如果你没有准备好,你的程序就会结束,因为它没有为你处理它。这当然假设您有一个能够检查的数组类。

标签: c++ arrays exception


【解决方案1】:

假设我真的不知道 a[5] 不起作用(或者用户输入了这个索引并且我没有检查数组大小),那么我怎样才能防止程序崩溃呢?

你根本做不到。对数组的越界访问会导致 C++ 中的未定义行为,它不会引发异常。当你足够幸运时,你会遇到崩溃。

【讨论】:

  • 啊,好吧。听起来很有希望! ;-)
  • 有趣的是,您说“它不会抛出异常”,但觉得有必要非常迂腐地回应我说“永远不会抛出异常”的评论。
  • @Ed S.:我同意,这当然很有趣!
  • ...我喜欢那个评论,+1:D
【解决方案2】:

抱歉,我忍不住引用了一个明显的模因“原生数组......这不是你做的!” :D

您在上面编写的代码使用本机数组,它本质上是一个内存位置。所以说 a[5] 你是说我想使用地址 (a + 4 * sizeof(int)) 处的 4 个字节来解释为一个 int。这不会抛出异常。这是未定义的行为,可能会返回垃圾。如果您使用 -O2 或类似的编译器标志,它可能返回 0 和 btw,这是缓冲区溢出的 A 级来源:D

这里有一个模板类可以解决你的问题:

#include <iostream>
#include <exception>
#include <stdexcept>
#include <vector>
using namespace std;

template<class T, size_t COUNT>
class CheckedArray
{
public:
    class OutOfBounds : public std::exception
    {
        public:
            virtual const char* what() const throw(){ return "Index is out of bounds"; }    
    };
    CheckedArray(){}
    virtual ~CheckedArray(){}
    const T& operator[] (size_t index) const
    {
        if(index >= COUNT){ throw OutOfBounds(); }
        return m_array[index];
    }
    T& operator[] (size_t index)    
    {
        if(index >= COUNT){ throw OutOfBounds(); }
        return m_array[index];
    }
private:
    T m_array[COUNT];
};
void arrayOutOfBound()
{
    //int a[3] = {1, 2, 3};

    CheckedArray<int,3> a;
    a[0] = 1;
    a[1] = 2;
    a[2] = 3;
    try
    {
        cout << "This should not display: " << a[5] << endl;
    }
    catch(std::exception& e)     // this will kick in
    {
        cout << "Error: " << e.what() << endl;
    }
}


int main()
{
    arrayOutOfBound();
}

【讨论】:

    【解决方案3】:

    如果您想要这种行为,建议您编写一个类,例如“CheckedArray”包装一个数组并执行边界检查。如果您完全笼统地这样做,它将是一个模板类,您当然需要了解重载 operator[]。

    或者,如果您对动态分配数组的开销感到满意,请使用std::vector,特别是其at 成员函数会在超出范围的索引上引发异常。作为附带的好处,您的数组现在可以在运行时(重新)调整大小。

    更好的是,使用std::array,它还具有抛出at 功能(但不可调整大小。)

    【讨论】:

    • 或者使用std::array之类的东西,已经全部存在了。
    • 我从 Deitel 的书中了解到,向量确实比我使用的数组更好。该示例仅用于错误处理。首先尝试使用 divideByZero() 但编译器设法做得很好。不幸的是,在这种情况下;-)
    【解决方案4】:

    如果您使用 std::array 而不是 C 样式数组和 .at() 成员函数,您可能会发现数组绑定错误

    std::array <int, 5> stdArray = {1, 2, 3, 4, 5};
    
    //array boundary check
    
     try  {
            cout << "trying to access out of bound element " << endl;
            cout << stdArray.at(5) << endl;
     } catch(std::exception &e) {
            cout << "Error: " << e.what() << endl;
      }
    

    现在程序没有崩溃,相反,你会看到这个输出 Error: array::at: __n (which is 5) &gt;= _Nm (which is 5)

    【讨论】:

      【解决方案5】:

      如果您只是想要一个处理分段错误等的处理程序,您应该查看 signal.h

      //约翰

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-12
        • 2017-09-24
        • 1970-01-01
        • 2014-01-10
        • 1970-01-01
        • 1970-01-01
        • 2011-10-02
        • 2019-01-03
        相关资源
        最近更新 更多