Click here to Skip to main content
15,904,024 members
Please Sign up or sign in to vote.
3.00/5 (3 votes)
See more:
Hi all,

I am in the process of making my library safe from exceptions.By this I mean when I get any exception - instead of having the library crashed or getting the system error messages,I want to return a error code back to the library user module.
This is how my class looks:
C++
#define BUFFER_SIZE 4096
class CSubClass1{
	private:BYTE *buffer;
	public:
	CSubClass1() {
		buffer = new BYTE[BUFFER_SIZE]; 
		if (buffer == NULL)
		throw 2;
	}
	
};
class CSubClass2{
	private:BYTE *buffer;
	public:
	CSubClass2() {
		buffer = new BYTE[BUFFER_SIZE]; 
		if (buffer == NULL)
		throw 3;
	}
	
};

class CMainClass{
	private:
	BYTE *buffer;
	CSubClass1 *obj1;
	CSubClass2 *obj2;
	public:
	CMainClass() {
		buffer = new BYTE[BUFFER_SIZE]; 
		if (buffer == NULL)
		throw 1;
	}
};

extern "C"  __declspec(dllexport) int function1() {
	StructUtilsSinglyLListNode	*newNode=NULL;
	try{
		newNode->pstData = new CMainClass();
	}
	catch(int retVal){
	UNREFERENCED_PARAMETER(retVal);//for my reference
	return 1;
	}
}
extern "C"  __declspec(dllexport) int function2() {
	StructUtilsSinglyLListNode	*newNode=NULL;
	//code will be present here to fetch node from global list
	//typecast it to CMainClass
	CMainClass *ptr =(CMainClass *) newNode->pstData;
	try{
		ptr->obj1 = new CSubClass1();
		ptr->obj2 = new CSubClass2();
	}
	catch(int retVal){
	UNREFERENCED_PARAMETER(retVal);//for my reference
	return 1;
	}
}


In the above code my doubt is:

In function2 when CSubClass1 or CSubClass2 are instantiated,if the memory on the heap is not available will the exception be thrown and caught on the exception handler?

Thanks in advance
Posted
Updated 28-Sep-11 0:55am
v2

Bad idea! Don't safeguard exceptions by handling them or turning into errors! It defeats the purpose of exceptions and means denial to use their power. Let them go.

Exceptions should be handled about the very top of the stack of each thread, more typically in application rather then in library. When an exception is caught in a deeper context, its propagation up to stack should not be prevented; as a rule of thumb, it should be re-thrown.

You can handle exceptions locally (deeper on stack) only in some special cases:

1) Exception should be processed in the library in a way known to the library but not to the code using the library. The exception could be successfully fully processed or re-thrown as a different exception, result of digesting of original exception. For example, in UI library, exception in user input could be totally covered by asking the user to re-enter the data until the data it corrected. I don't say this is the best practice, but it can be accepted. In other cases, raw exception could be re-thrown as a different, "semantic" exception. For example, failure to process a string in a wrong format could be re-worked in the exception suggesting the list of valid formats.

2) Exception thrown is some "bad" code could be handled and not re-thrown to compensate the defects in the API used, in case there is no way to patch it. Still, it's the best not to break the exception propagation unattended. You can write it in the system log or something like that.

3) Exception is thrown in a DLL, but the code using the DLL can be written in different language with different or no exception system. Only then your approach could be applied.

—SA
 
Share this answer
 
v2
Comments
hakz.code 28-Sep-11 2:43am    
Hi,If the memory allocation in constructor fails then I want the caller module of the library to know that, or I need to know that - so that I dont continue using the bad memory which may result in crash.So I thought to handle these crashes.As constructor doesnt return a value,I wanted in some way to know that the allocation is not successful.How can I handle these things without the help of exception handlers(try,catch,throw - since it is c++ library),and if the caller module doesnt catch them it would be a runtime error right?
Sergey Alexandrovich Kryukov 28-Sep-11 12:03pm    
Who says "without the help of exception handlers"? Not using them defeats exceptions exactly as catching them as soon as they appear. You should use them, but late as possible. Allocation failure is yet another case for it.

If you catch them at the place of allocation, there will be no use -- you cannot "create" extra memory. So, again the using code can handle it. Operation failed due to insufficient memory, for example. The top user can better chance to decide what to do. It's pointless to repeat operation again, but the user will know that there is not enough memory for it. In this case, the user may decide to delete some other objects... Memory allocation problem is one of the hardest though. You need to prevent half-allocated object, so you can use local exception handling to make sure partially allocated stuff is deleted, but re-throw exception. In you can do it, it will be the case #1.

--SA
Stefan_Lang 28-Sep-11 4:23am    
While I agree that using exceptions is the better idiom than using error codes, isn't the OPs case a perfect example for case 3? At least the function declarations do look like a library API, and they might indeed be callable from other language modules. (or maybe not? I never tried to bind modules from different languages...)
Sergey Alexandrovich Kryukov 28-Sep-11 11:55am    
Maybe, I'm not sure. For this case, some "exception thunk" should be created if calling executable has different exception implementation: get error information and immediately turn it into exception again.
--SA
Stefan_Lang 28-Sep-11 12:03pm    
If the error code you generate from the exceptions could be used to retrieve extended information (about the original exceptions), would that satisfy your requirements? It would of course require one additional function in the library API and some data structure to store exception details. But otherwise it would resemble the OPs suggestion.
Operator new doesn't return NULL on failure, it throws the std::bad_alloc exception. That makes your tests and throw statements useless and redundant. Because you're not catching bad_alloc, it's propagated to the caller of your functions.
 
Share this answer
 
As mentionned in other solutions, this is a very bad idea that show you didn't yet understand the purpose and working of exceptions... and you are trying to work around them because of that.

I would suggest you to learn about exception by reading books or tutorial. In real life and in particular in C++, you rarely have to do anything about exception if the code is properly done except writing something to the user when a command cannot be completed.

As others have mentionned, the purpose of exception is exactly the opposite of what you are trying to do. The purpose is to avoid the using of error codes that are seldom checked and make the regular code complex to understand because regular logic is mixed with error logic.

Here is a few things you might want to check:

http://en.wikipedia.org/wiki/Exception_handling[^]

http://www.parashift.com/c++-faq-lite/exceptions.html[^]

http://msdn.microsoft.com/en-us/library/4t3saedz.aspx[^]

And if you like to read books, then book like Exceptional C++[^] would be a recommanded reading.
 
Share this answer
 
Comments
Philippe Mori 27-Sep-11 22:25pm    
After thinking of it, I have added a solution for when it is a necessity like in a DLL that must be used by an application that does not support exception (and the application cannot be modified).
hakz.code 28-Sep-11 3:00am    
Hi ,thanks for the suggestion,I have gone through this link - http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.8 before asking the question. As suggested there - "Constructors don't have a return type, so it's not possible to use return codes. The best way to signal constructor failure is therefore to throw an exception",I did the above coding.My doubt was - If the memory allocation in constructor fails then I want the caller module of the library to know that, or I need to know that - so that I dont continue using the bad memory which may result in crash.So I thought to handle these crashes.As constructor doesnt return a value,I wanted in some way to know that the allocation is not successful.How can I handle these things without the help of exception handlers(try,catch,throw - since it is c++ library),and if the caller module doesnt catch them it would be a runtime error right?
Philippe Mori 28-Sep-11 8:22am    
new already thrown an exception so you don't have to catch it and throw something else.
Stefan_Lang 28-Sep-11 4:37am    
Side question: I stumbled upon a link to GOTW ( http://www.gotw.ca/gotw/ ) and bit by bit digested it's contents. The site explains that the cases presented there are the main content of Exceptional C++ and the folow-ups. I now wonder, if I did have no trouble understanding all of GOTW, is it still recommendable to read the book?

I suspect it might, since why should all the relevant content be posted for free on this site if it meant you didn't have to buy the book(s) anymore...
hakz.code 28-Sep-11 5:09am    
I didnt get your point !
If you absolutly need to prevent exceptions from being thrown outside the DLL maybe because it is used by a different compiler or by a program that uses your DLL as a plug-in , then you should typically do something like that:

C++
int SafeExecute(void (*fn)())
{
    try
    {
       fn();
    }
    catch (const std::bad_alloc &)
    {
        return ERROR_CODE_FOR_OUT_OF_MEMORY;
    }
    catch (const std::exception &)
    {
        return ERROR_CODE_FOR_GENERIC_EXCEPTION;
    }
    return ERROR_CODE_NONE;
}


If you use a library like MFC that uses other exceptions or handle SEH exceptions, you should add them to the above catch (remember that catch are tried in order until a match is found).

Then for each of your function, you would done something like:
C++
void function1_impl()
{
    // code that might throw exceptions...
}

int function1()
{
    return SafeExecute(&function1_impl);
}


There are possible variations on this using macros and/or testing exceptions by rethrowing them.

In COM/ActiveX days, it was common to do so because the Component Object Model didn't support exceptions. There was also a way to report error text.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900