Few questions about error handling....conditional inclusions and more.

Started by
6 comments, last by frob 14 years, 5 months ago
Hi. I have a few questions about how to handle errors in... 1) Lets say I have a function call like and it would be in my best intrest if I check to see if the call to the function produces the proper results. Would I wrap the "checking" version in a conditional inclusion? This way the funtion is only checked when I define that inclusion. For example
#ifdef DEBUG
	if( hr = FAILED( D3DXCreateFontIndirect(m_graphicsReference->Get3DDevice(), 
							&lf, 
							&m_fonts[tempID] ) ) )
	m_graphicsReference->GetApplication()->GetError().ProcessError(hr);

#else
	D3DXCreateFontIndirect(m_graphicsReference->Get3DDevice(), 
							&lf, 
							&m_fonts[tempID] )
#endif
Is this a common practice? To put conditional inclusion through out your code? 1) Is there any way to gather information about where you are currntly in the program. If you notice in the code above when DEBUG is defined and the function call fails the Error is sent off to an Errror handling function. I was wondering if there was a way to also gather information as to where the error has occured in the program (What function? What Class?) allowing me to also provide that feedback to the user of the Error handling class. Regards Chad
Advertisement
Quote:Original post by chadsxe
Hi.

I have a few questions about how to handle errors in...

1) Lets say I have a function call like and it would be in my best intrest if I check to see if the call to the function produces the proper results. Would I wrap the "checking" version in a conditional inclusion? This way the funtion is only checked when I define that inclusion. For example*** Source Snippet Removed ***Is this a common practice? To put conditional inclusion through out your code?

1) Is there any way to gather information about where you are currntly in the program. If you notice in the code above when DEBUG is defined and the function call fails the Error is sent off to an Errror handling function. I was wondering if there was a way to also gather information as to where the error has occured in the program (What function? What Class?) allowing me to also provide that feedback to the user of the Error handling class.
Sort of. That's the sort of thing you use asserts for. The assert macro is a macro that does nothing in final / release builds, but causes a break to the debugger in debug builds. That allows the user to use the debugger to see where it went wrong.

You need to be able to distinguish between errors you can ignore, and errors you can't ignore. If D3DXCreateFontIndirect() fails, then m_fonts[tempID] will be a null pointer. If your code assumes that m_fonts[tempID] is a valid pointer, then in release builds you'll get a crash.
For D3D, it's common to leave most of your error checking in, even for release builds, and to use a macro that asserts() that a D3D function succeeds in debug builds for non-critical calls (E.g. most SetRenderState() calls).
Quote:Original post by chadsxe
Is this a common practice? To put conditional inclusion through out your code?

No. Always check for errors wherever feasible and a good idea, and handle them appropriately. Checking for D3DXCreateFontIndirect failing is definitely something you want to do, even in the retail build of your application.

Quote:Is there any way to gather information about where you are currntly in the program.

Most compilers will have predefined 'magic' macros, like __FILE__ and __LINE__, that will expand out to give location information based on the line they are placed on. Check your compiler's documentation.

Also, consider throwing an exception as an alternative to calling a callback to handle the error (here you're still continuing execution after calling ProcessError!)
Quote:Original post by mattd
Most compilers will have predefined 'magic' macros, like __FILE__ and __LINE__


The macros are required by the standard, so they should be present in ALL compilers. If they are missing, it is a compiler bug.

The often used values are:

__FILE__ is the (presumed) named of the source file ("filename.cpp")
__LINE__ is a decimal constant of the current source line (42)
__DATE__ is the date it was compiled ("Mmm dd yyyy")
__TIME__ is the time it was compiled ("hh:mm:ss")

The first two are nice for tracking where events happen. The second two are useful in tracking versions of the compiled code.
Trying to take this in and ran into my first problem.

Lets say I am doing something like this
hr = FAILED( D3DXCreateFontIndirect(m_graphicsReference->Get3DDevice(),           &lf,           &m_fonts[tempID] ) ) ;	ASSERT(hr == S_OK);
Error.h
#pragma once#ifndef DEBUG	#define ASSERT(x)#else	#define ASSERT(x) 		if (! (x) ) 		{ 		}#endifclass Error{public:	Error();	~Error();	static void DebugString(const std::wstring &str);	void ProcessError(HRESULT hr);};
How do I call ProcessError from inside my ASSERT MACRO, and for that matter how do I pass the HRESULT to the MACRO so the MACRO can pass it to ProcessError().

Regards

Chad
Macros aren't magic.

Quote:Original post by chadsxe
How do I call ProcessError from inside my ASSERT MACRO

Create or retrieve an instance of Error, and call its ProcessError method.

Quote:how do I pass the HRESULT to the MACRO so the MACRO can pass it to ProcessError()

Add another parameter to your ASSERT macro that is used to pass in the HRESULT on to ProcessError. You'll need to explicitly pass in hr in every call to ASSERT yourself, like this:
#define ASSERT(expr, hr) do { if(!(expr)) error.ProcessError(hr); } while(0)// To use..ASSERT(hr == S_OK, hr);


That said, why are you not using the standard assert macro defined in <cassert>? It will be provided by your compiler vendor, and hence will probably do useful things like include file and line information, the expression that's causing the assertion, and break into the debugger if one is attached.

Also, have you looked at exceptions yet? :)

(As an aside, I'm pretty sure FAILED returns a boolean (or at least boolean-like) value, so assigning it to hr doesn't make sense.)

[Edited by - mattd on November 6, 2009 12:45:55 PM]
Quote:Original post by mattd

Quote:Create or retrieve an instance of Error, and call its ProcessError method.

I apologize but I am not following. You are saying I need to create or retrieve an instance of Error from with inside my macro correct? If this is the case would it not have to be global? I can't create an instance inside the macro and I can't retrive an instance via a function because my function are incompassed inside a class.

I am still looking into exceptions as well.

Also thanks for the heads up on FAIL.

EDIT: For that matter can you #define in side of a class?

EDIT AGAIN: The reason why I was not using the standard assert macro is because I wanted to print out some custom information in regards to what kinda of DX result was being given.

Regards

Chad

[Edited by - chadsxe on November 6, 2009 12:04:42 PM]
Quote:How do I call ProcessError from inside my ASSERT MACRO, and for that matter how do I pass the HRESULT to the MACRO so the MACRO can pass it to ProcessError().
Your custom assert macro would need to just use it.

Pulling from your example, but renaming the assertion so it doesn't collide:
#ifndef DEBUG   #define CHADS_ASSERT(expression, message) {((void)0);}#else   #define CHADS_ASSERT(expression, message)  {if (! (expression) ) { DoAssertionHandling( #expression, message, __FILE__, __LINE__ ); } }#endif


If you wanted to pass it an HRESULT value, you would need to add it to your assertion, perhaps in the form
#define CHADS_ASSERT(expression, hresult, message)  { if (! (expression) ) { DoAssertionHandling( #expression, hresult, message, __FILE__, __LINE__ ); } }


Quote:For that matter can you #define in side of a class?

Yes, you can define a macro on any line.

The preprocessor looks for lines beginning with "#".

The preprocessor does not know or care about the program structure. It does not respect scope. It does not know or care about type safety, correctness, or any other programming issue. The preprocessor operates on "lines" of tokens after the text has gone through the lexical analysis. The preprocessor lines have no syntactic significance. The preprocessor is little more than a glorified engine to perform copy/cut/paste within your source code.

Quote:The reason why I was not using the standard assert macro is because I wanted to print out some custom information in regards to what kinda of DX result was being given.
Printing out error messages is a longing functionality. It is best considered separately from error handling or assertions.

There are many logging systems out there or you can write your own. The best ones allow you to have multiple logging streams and verbosity settings. Something where you can control which set of output to view (e.g. DebugD3DStream, DebugUI) what level of detail the message is (e.g. always, warning, trace, verbose) and so on.
Log( DebugD3DStream, Logging::verbose, message );
This allows you to start and stop listening to messages at any time, redirect them to files or to the screen, and turn on additional details whenever you need it.

This topic is closed to new replies.

Advertisement