【问题标题】:C++: Catch block not catching?C++:Catch 块没有捕获?
【发布时间】:2011-10-23 16:56:14
【问题描述】:

我有一个特定的异常类,我想从类方法中抛出并从 main() 函数中的调用代码中捕获。

但是,当我运行它时,我收到以下错误: Unhandled exception at 0x775915ee in OpenHashTable.exe: 0xC0000005: Access violation. 好像它没有被处理。我不明白为什么会这样。以下是相关代码:

main() {
    ......
        case 'i':   
        {
                cout << "Enter the positive integer you wish to insert: ";
                    //Input Validation.  
                if (!(cin >> number))
                {
                    cout << "Please enter a valid positive integer...\n\n";
                    cin.clear();
                    cin.ignore(numeric_limits<streamsize>::max(), '\n'); //Taken from http://stackoverflow.com/questions/2075898/good-input-validation-loop-using-cin-c
                    break;
                }
                try
                {
                    hashTable.add(abs(number)); //Add positive only integer
                }
                catch (FullTableException& fte)
                {
                    cout << "HashTable is full!" << endl;
                    break;
                }
                catch (DuplicateElementException& dee) //NOT BEING CAUGHT?
                {
                    cout << "HashTable already contains that element." << endl;     
                    break;
                }
                cout << abs(number) << " added!\n\n";
                break;
        }
     .......
}

这是 HashTable::add() 方法中抛出的异常

    //Adds an element into the appropriate index
bool OpenHashTable::add(int toAdd) throw(FullTableException, DuplicateElementException)
{
  int index = hash(toAdd);

  //Check for duplicate
  if (search(toAdd))
      throw DuplicateElementException();  //NOT ACTUALLY THROWING??

  if (arr[index] != 0) //If element is occupied   //GET AN ACCESS VIOLATION HERE
  {
      int j = 0;

      //Linear Probing...
      for ( unsigned int i = index + 1; j < 100; i = ((i+1) % 100) )
      {
          if (arr[i] != 0 && arr[i] != -1) //If element is occupied
          {
              j++;          //Keep count of how many tries, for full array
              continue;
          }
          else
          {
              arr[i] = toAdd;   //Add to array
              size++;           //Increment size
              break;
          }

      }
      if (j == 100) //We've checked all possible elements
          throw FullTableException();   //No spaces
  }
  else
  {
      arr[index] = toAdd;   //Add to array straight away
      size++;               //Increment size
  }
  return true;  //Successfully added

}

编辑:search() 方法:

    bool OpenHashTable::search(int toSearch)
{
    int index = hash(toSearch);

if (arr[index] == toSearch)
    return true;    //Found at index
else
{
    int j = 0;
        //Linear search for value
    for ( unsigned int i = index + 1; j < 100; i = ((i+1) % 100) )
    {
        if (arr[i] == toSearch)
            return true;    //found
        else if (arr[i] == 0)
            return false;   //Not in HashTable
        else 
            continue;   //Probe next element
    }
    if (j == 100)
        return false;   //Not in HashTable
}
return true;
}

编辑:_尝试..._except() 调用堆栈:

    ntdll.dll!775915ee()    
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] 
ntdll.dll!775915ee()    
ntdll.dll!7761852f()    
ntdll.dll!776372ec()    
ntdll.dll!7760063e()    
ntdll.dll!775fabf9()    
ntdll.dll!77580143()    
KernelBase.dll!75c5b9bc()   
KernelBase.dll!75c5b9bc()   
KernelBase.dll!75c5b9bc()   
msvcr100d.dll!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo)  Line 157   C++
OpenHashTable.exe!OpenHashTable::add(int toAdd)  Line 100   //THIS IS "throw DuplicateElementException()"

OpenHashTable.exe!main()  Line 267    //THIS IS "hashTable.add(abs(number));"

编辑:重复元素异常:

//Just an empty class
class DuplicateElementException : public exception
{
private:
public:
    DuplicateElementException();   //Constructor
    ~DuplicateElementException();   //Destructor
};
//empty constructor and destructor definitions...

非常感谢任何帮助。

谢谢

卡鲁姆

【问题讨论】:

  • 您的搜索方法是什么?另外,您不应该根据表大小来修改哈希值吗?
  • 已添加。不明白你的意思。哈希函数就是value % 100(100 是表大小)
  • 请发DuplicateElementException的内容
  • 当用户输入非数字(如f)时代码中存在错误
  • 当键不在表中时,您的搜索是一个无限循环

标签: c++ oop exception exception-handling try-catch


【解决方案1】:

抛出的异常是 SEH 异常“访问冲突”,这意味着您从无效地址读取或写入。这可能是searchhash 中的错误。并且你的程序没有到达你抛出 DuplicateElementException 的那一行。

此外,异常规范(函数原型之后的抛出)已被弃用,所以不要使用它们。

【讨论】:

  • 大多数编译器并没有以符合标准的方式实现异常规范,但是它们是否已正式弃用?
  • 感谢您的更新。他们是时候摆脱这些了 :)
  • search() 方法已添加,看不到错误。在调试中,它似乎确实进入了if (search(toAdd)) 并且在throw 语句上失败了。啊,我不知道弃用,谢谢。
  • @CalumMurray:根据我们掌握的信息,这听起来是不可能的。所以要么你误解了你所看到的并给我们提供了错误的信息,要么在低层上真的有问题。我只能建议您调试生成的程序集以确定真正的问题。这就是我会做的。
【解决方案2】:

抛出的访问冲突异常是一个 SEH 异常,不会被 C++ catch 块捕获。您很可能超出了某个数组的范围,这会导致抛出异常。

要调试问题,请将 main 内代码中的所有内容包含在 __try 块中,并在随附的 __except 块中放置断点。可以在MSDN docs 中找到有关如何执行此操作的详细信息。您几乎可以逐字使用其中的代码。在调试模式下运行您的程序,并在命中断点时检查调用堆栈以确定 SEH 异常在哪一行被抛出。

此外,除非您有非常令人信服的理由使用 C 数组,否则您应该使用 std::array(如果数组的大小是固定的)或 std::vector 用于哈希表。在 Visual Studio operator[] 上,这两个都将在调试模式下执行范围检查,如果您的索引超出范围,则抛出 std::out_of_range 异常。您还可以将at() 成员函数与两者一起使用,以使它们也在发布模式下执行边界检查。无论哪种情况,调试都比弄乱 SEH 的东西要容易得多。

编辑:
使用__try - __except 调试问题需要进行一些代码重构,因为您不能使用__try 包围包含C++ 对象破坏的代码。

要解决此问题,请创建一个名为 int mainHelper() 的函数,并将 main 中的所有代码移至此函数。现在,您的代码应如下所示:

int mainHelper()
{
  /* All your code from main goes here */
}

int main()
{
  __try {
    return mainHelper();

  } __except( filter(GetExceptionCode(), GetExceptionInformation()) ) {
    puts("in except");

  }
}

【讨论】:

  • 顺便说一句,使用 /EHa 编译时,可以使用 catch(...) 捕获 SEH。
  • @ybungalobill 可以,但我记得在某处读到该选项并不是非常理想的设置。不幸的是,我不记得所陈述的原因。
  • 谢谢。我不确定在__except(expression) 语句中要表达什么。我只在大小为 100 的数组中使用索引 3,所以我看不到在哪里生成数组越界错误。
  • @CalumMurray 复制粘贴filter() 函数,如上所示main 并将filter(GetExceptionCode(), GetExceptionInformation()) 放入__except 表达式中。您不必使用该示例中显示的内部 __try - __finally 构造。其他一切都可以保持不变。在puts("in except");行上打断点
  • 哦,是的,谢谢。当我将所有代码包装在 main() 函数中时,我得到了 Cannot use __try in functions that require object unwinding
【解决方案3】:

似乎索引超出了数组 arr 的范围。它使您的进程从未分配给它的内存中读取并崩溃。这不是 C++ 异常,而是操作系统告诉您的程序。

【讨论】:

  • 我看不出我怎么能越界访问。我用索引 3 测试它,数组大小为 100。
  • @CalumMurray 你有两行代码: int index = hash(toSearch); if (arr[index] == toSearch) 您应该在访问 arr[index] 之前检查 hash(toSearch) 返回的内容。
  • 你如何声明大小为 100 的 arr? (我在你粘贴的代码中看不到)
【解决方案4】:

有一种非常简单的方法可以在 Visual Studio 中使用 try -> catch (...) 块来捕获任何类型的异常(除以零、访问冲突等)。一个小的项目调整就足够了。只需在项目设置中启用 /EHa 选项。请参阅项目属性 -> C/C++ -> 代码生成 -> 将 Enable C++ Exceptions 修改为“Yes With SEH Exceptions”。就是这样!

在此处查看详细信息: http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx

【讨论】:

  • 您提供了一个可能很危险的解决方案,却没有说出它的缺点。
  • 我不知道缺点。如果你知道,为什么不告诉你?对我来说,这个解决方案非常完美,比这里投票更高的解决方案要好得多。
  • /EHa 可能会导致您的程序在内存访问越界、被零除或其他异步 (SEH) 异常之后混乱地与损坏状态混淆。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-26
  • 2019-07-12
  • 1970-01-01
  • 2019-11-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多