Try catch help

Started by
10 comments, last by Zahlman 19 years ago
Okay, so I'm defining the methods of class 'Image' in cImage.cpp, and I decide to use try-catch blocks. Inside each function I have a try block and if making the SDL_Surface fails I throw an error string (STL string, it's a class member) that contains information on what happened. Then after all the functions I have the catch block that writes the error to a file. I got compiler errors because my catch was apparently too many code blocks above my trys so I created intermediate catch blocks that threw to the final catch. Here is the code for that:

//Includes
#include "../headers/cImage.h"

namespace AS
{
    
  cImage::cImage()
  {
    this->Source = NULL;
    this->Dest = NULL;
  }
  
  cImage::cImage(string File, SDL_Surface *Dest)
  {
      if(!(this->Dest = Dest))
      {
        Error = "Invalid dest. surface initialized";
        throw (Error);
      }
      LoadFromFile(File);
  }
  
  cImage::cImage(SDL_Surface *Source, SDL_Surface *Dest)
  {
    try
    {
      if(!(this->Source = Source))
      {
        Error = "Invalid source surface initialized";
        throw (Error);
      }
      
      if(!(this->Dest = Dest))
      {
        Error = "Invalid dest. surface initialized";
        throw (Error);
      }
    }
    catch (string s)
    {
      throw (s);
    }
  }
  
  cImage::cImage(SDL_Surface *Source, SDL_Surface *Dest, int w, int h, int x, int y)
  {
    this->Dimensions.w = w;
    this->Dimensions.h = h;
    this->Dimensions.x = x;
    this->Dimensions.y = y;
    
    try
    {
      if(!(this->Source = Source))
      {
        Error = "Invalid source surface initialized";
        throw (Error);
      }
      
      if(!(this->Dest = Dest))
      {
        Error = "Invalid dest. surface initialized";
        throw (Error);
      }
    }
    
    catch(string s)
    {
      throw(s);
    }
  }
  
  void cImage::Draw()
  {
    SDL_BlitSurface(Source, &Dimensions, Dest, &Location);
  }
  
  void cImage::Draw(int x, int y)
  {
    SetLocation(x, y);
    SDL_BlitSurface(Source, &Dimensions, Dest, &Location);
  }
  
  void cImage::SetSource(SDL_Surface *Source)
  {
    try
    {
      if(!(this->Source = Source))
      {
        Error = "Invalid source surface initialized";
        throw (Error);
      }
    }
    
    catch(string s)
    {
      throw(s);
    }
  }
  
  void cImage::SetDest(SDL_Surface *Dest)
  {
    try
    {
      if(!(this->Dest = Dest))
      {
        Error = "Invalid dest. surface initialized";
        throw (Error);
      }
    }
    
    catch(string s)
    {
      throw(s);
    }
  }
  
  void cImage::LoadFromFile(string FileName)
  { 
    //Turn the filename into a character array from a string
    char *ConvertedFileName;
    stringstream stream(FileName);
    stream >> ConvertedFileName;
    //load the BMP file
    this->Source = SDL_LoadBMP(ConvertedFileName); 
    
    try
    {
      if(Source == NULL)
      Error = "Invalid bitmap file.";
      throw (Error);
    }
    
    catch(string s)
    {
      throw(s);
    }
  }
  
  void cImage::SetDimensions(int w, int h, int x, int y)
  {
    this->Dimensions.w = w;
    this->Dimensions.h = h;
    this->Dimensions.x = x;
    this->Dimensions.y = y;
  }
  
  void cImage::SetLocation(int x, int y)
  {
    this->Location.x = x;
    this->Location.y = y;
  }
  
  //Catch Block
  catch (string)
  {
    fstream ErrorFile("ErrorLog.txt", ios::out);
    ErrorFile << string << endl << "-------------------------------" << endl;
    ErrorFile.close();
  }
    
} //End Namespace AS


I get the syntax error 'syntax error before catch' that directs me to the final catch block. How should I handle try catch in this situation? Also, in the catch block is there a way I could call the destructor (not implemented yet) before I quit? Thanks for any help.
Advertisement
You could structure it like this:
try{	// Make some error	throw std::string("Some error!");}catch(std::string error){	std::cout << error;}


... Also....

// This:cImage::cImage(SDL_Surface *Source, SDL_Surface *Dest)  {    try    {      if(!(this->Source = Source))      {        Error = "Invalid source surface initialized";        throw (Error);      }            if(!(this->Dest = Dest))      {        Error = "Invalid dest. surface initialized";        throw (Error);      }    }    catch (string s)    {      throw (s);    }  }// Should be:cImage::cImage(SDL_Surface *Source, SDL_Surface *Dest)  {      if(!(this->Source = Source))        throw std::string("Invalid source surface initialized");                  if(!(this->Dest = Dest))        throw std::string("Invalid dest. surface initialized");        }// Then when you are working with making the images and stuff// just make sure you surround them in a try catch block:try {      cImage* image = new cImage(source, dest);}catch(std::string error){      // Caught the error - failed loading?}


... But of course you should create derived error classes from std::exception.
Rob Loach [Website] [Projects] [Contact]
First of all, why are you surrounding your code with try/catch blocks, which promptly rethrow the error? Don't, it's a silly waste of code.

Secondly, you really should be throwing a type derived from std::exception. It's a much better practice than throwing around strings, also tends to mean that when someone else uses or looks at the code, it will make much more sense.

As for the error: you have a catch block with no try block.

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.

Quote:
First of all, why are you surrounding your code with try/catch blocks, which promptly rethrow the error? Don't, it's a silly waste of code.

That's the problem, I don't want to duplicate my error code for each function and I don't know how to elegantly make all my code go to one catch block. How do I do that? Also, could you show me how you would derive from std::exception? I've never done that before and don't really know why I would want to.
//Includes#include "../headers/cImage.h"namespace AS{	class ImageException : std::exception {	public:		ImageException(std::string const& error) : std::exception(error.c_str()) {}	};	cImage::cImage()	{		this->Source = NULL;		this->Dest = NULL;	}	cImage::cImage(string File, SDL_Surface *Dest)	{		if(!(this->Dest = Dest))		{			throw ImageException("Invalid dest. surface initialized");		}		LoadFromFile(File);	}	cImage::cImage(SDL_Surface *Source, SDL_Surface *Dest)	{		if(!(this->Source = Source))		{			throw ImageException("Invalid source surface initialized");		}		if(!(this->Dest = Dest))		{			throw ImageException("Invalid dest. surface initialized");		}	}	cImage::cImage(SDL_Surface *Source, SDL_Surface *Dest, int w, int h, int x, int y)	{		this->Dimensions.w = w;		this->Dimensions.h = h;		this->Dimensions.x = x;		this->Dimensions.y = y;		if(!(this->Source = Source))		{			throw ImageException("Invalid source surface initialized");		}		if(!(this->Dest = Dest))		{			Error = "Invalid dest. surface initialized";			throw (Error);		}	}	void cImage::Draw()	{		SDL_BlitSurface(Source, &Dimensions, Dest, &Location);	}	void cImage::Draw(int x, int y)	{		SetLocation(x, y);		SDL_BlitSurface(Source, &Dimensions, Dest, &Location);	}	void cImage::SetSource(SDL_Surface *Source)	{		if(!(this->Source = Source))		{			throw ImageException("Invalid source surface initialized");		}	}	void cImage::SetDest(SDL_Surface *Dest)	{		if(!(this->Dest = Dest))		{			throw ImageException("Invalid dest. surface initialized");		}	}	void cImage::LoadFromFile(string FileName)	{ 		//Turn the filename into a character array from a string		char *ConvertedFileName;		stringstream stream(FileName);		stream >> ConvertedFileName;		//load the BMP file		this->Source = SDL_LoadBMP(ConvertedFileName); 		if(Source == NULL) {			throw ("Invalid bitmap file.");		}	}	void cImage::SetDimensions(int w, int h, int x, int y)	{		this->Dimensions.w = w;		this->Dimensions.h = h;		this->Dimensions.x = x;		this->Dimensions.y = y;	}	void cImage::SetLocation(int x, int y)	{		this->Location.x = x;		this->Location.y = y;	}}///Sample usage:try {	std::auto_ptr<AS::cImage> img(new AS::cImage());	img->LoadFromFile("file that can't be found");} catch(AS::ImageException& exception) {	std::cout<<exception.what();}


When you throw an exception, it will automatically propagate up the call stack until it encounters a catch block that will handle it. This means that if any of those functions throws, it will work it's way up the call stack until it gets to my catch block. This is the entire point of exceptions, it simplifies error handling. Otherwise it would be no better than C error handling (return -1, test for -1, return -1, etc)

I should note that the exception class SHOULD be in the header, not in the source file, so that code that uses cImage can see the exception class.

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.

Thank you very much Washu, this will greatly improve my code.

Just a question though, is there any way to put the catch block in the class implementation instead of relying on the user to create one?
Sure, but why would you? It is the users responsibility to catch and handle the errors, as they know how they wish the application to respond. If they don't handle it, well, they will find out pretty soon that they need to.

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.

Thanks, I understand now.

What more would I have to do to get your exception class to work though? I've been fiddling with it, but std::excpetion::exception() (constructor) doens't take any arguments, so I don't know why your initializer list is set up to send a c-string. Is my compilers' STL implementation faulty?

Here's how it's set up:
  class exception   {  public:    exception() throw() { }    virtual ~exception() throw();    /** Returns a C-style character string describing the general cause     *  of the current error.  */    virtual const char* what() const throw();  };


It's constructor doesn't actually do anything, and I don't see how I would use it.

Oh, and when I try to compile it gives me a dozen errors saying that I have to have one catch per try block, so it won't work. That's why I had the original system.

[Edited by - Drakkcon on March 29, 2005 5:41:57 PM]
Nevermind, problem solved. I learned a new thing today: don't use try blocks in a file without a catch (I thought that in order to use throw you had to use try but instead it's in order to use catch, stupid me). Thanks everyone, all.rate++.
Still having trouble with the exception class though.
forget it. I inherited from runtime_error instead of Exception. This solved my problem! Thanks for the help washu.

This topic is closed to new replies.

Advertisement