Calum Murray
Calum Murray

Reputation: 1192

C++: Catch block not catching?

I've got a specific Exception class I'm wanting to throw from a class method and catch from it's calling code in the main() function.

However when I run it, I get the following error: Unhandled exception at 0x775915ee in OpenHashTable.exe: 0xC0000005: Access violation. as if it isn't being handled. I can't see why this is happeing. Here's the involved code:

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;
        }
     .......
}

Here's the exception being thrown in the HashTable::add() method

    //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

}

EDIT: search() method:

    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;
}

EDIT: _try..._except() Call Stack:

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

EDIT: DuplicateElementException:

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

Any help is much appreciated.

Thanks

Calum

Upvotes: 0

Views: 1958

Answers (4)

Volodymyr Frytskyy
Volodymyr Frytskyy

Reputation: 1303

There is a very easy way to catch any kind of exception (division by zero, access violation, etc.) in Visual Studio using try -> catch (...) block. A minor project tweaking is enough. Just enable /EHa option in project settings. See Project Properties -> C/C++ -> Code Generation -> Modify the Enable C++ Exceptions to "Yes With SEH Exceptions". That's it!

See details here: http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx

Upvotes: -2

Praetorian
Praetorian

Reputation: 109289

The Access violation exception being thrown is an SEH exception and will not be caught by a C++ catch block. You're most likely writing beyond the bounds of some array, which is causing the exception to be thrown.

To debug the problem, surround everything within the code inside main in a __try block and place breakpoints within the accompanying __except block. Details of how to do this can be found in the MSDN docs. You can use the code in there almost verbatim. Run your program in Debug mode and when the breakpoint is hit inspect the call stack to figure out what line the SEH exception is being thrown at.

Also, unless you have a very compelling reason to be using a C array, you should be using an std::array (if the size of the array is fixed) or an std::vector for the hash table. On Visual Studio operator[] for both of these will perform range checks in Debug mode and throw an std::out_of_range exception if your index is out of bounds. You can also use the at() member function with both to have them perform bounds checking in Release mode also. In either case, it is a lot easier to debug than having to mess with the SEH stuff.

EDIT:
A little bit of code refactoring will be required to debug the problem using __try - __except because you cannot surround code containing C++ object destruction with __try.

To get around this, create a function called int mainHelper() and move all the code from within main to this function. Now, your code should look like this:

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

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

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

  }
}

Upvotes: 4

selalerer
selalerer

Reputation: 3934

It seems like index is out of bound of the array arr. It makes your process read from memory that isn't allocated to it and crash. This is not a C++ exception but something the OS tells your program.

Upvotes: 0

Yakov Galka
Yakov Galka

Reputation: 72539

The exception thrown is a SEH exception "Access violation", which means that you read or write from an invalid address. It's probably a bug in search or hash. and your program doesn't get to the line where you throw DuplicateElementException.

Besides, exception specification (the throw after the function prototype) are deprecated, so don't use them.

Upvotes: 5

Related Questions