I'm developing a C++ DLL that allocate an array for the main application.
The function return an error code and not the pointer to the new created array, so the address of the first member will be written in a parameter of the function.
Example:
int foo(int** arrayPtr) {
int* array = new int[10];
*arrayPtr = array;
return 0;
}
So, in the main I call the function that way:
int* myArray;
int ret;
ret = foo(&myArray);
Now myArray points to the new created array.
QUESTION 1: Is there a better way to do this?
Than the more interesting question.
If I pass NULL as parameter for foo, I generate an Access Violation exception because
*arrayPtr = array;
will try to write in 0x00000.
So, I added a try-catch block
int foo(int** arrayPtr) {
int* array = new int[10];
try {
*arrayPtr = array;
} catch(...) {
return 1;
}
return 0;
}
I expect that , when I call foo with NULL as parameter, it will return 1. Not true! It generate an exception.
QUESTION 2: Why the try-catch block in the DLL doesn't work?
Thanks to everyone!
P.S.: using try-catch for generating the same exception directly in the main doesn't generate an exception (or better, it's correctly handled by the try-catch block).
Assuming you're using VC++, try..catch
will not catch access violations by default because the default exception handling model only catches synchronous exceptions and access violations are asynchronous exceptions. This is documented here: /EH (Exception Handling Model)
If you change your project settings to use /EHa
instead of /EHsc
then your try..catch
will catch the access violation.
That said, why not explicitly check for NULL
? Using exceptions for flow control is bad form.
int foo(int** arrayPtr) {
if (!arrayPtr)
return 1;
*arrayPtr = new int[10];
return 0;
}
To question 1:
I don't see what is bad with the function. Can you define what you mean with better.
You could use std::shared_ptr with an array type or boost::shared_array to have a better resource handling. But this depends on the interface you want to use.
To question 2:
try {
*arrayPtr = array;
} catch(...) {
return 1;
}
When arrayPtr is NULL this will create an access violation. You cannot catch those with c++ try/catch blocks.
- The other option is to return the pointer instead of a code. Returning NULL for a failed allocation seems pretty obvious.
2a. Passing NULL to your function seems more like an error on the calling side. Terminating the program with access violation in not unreasonable. That will show the caller where his error is!
2b. A catch clause can only catch exceptions that are thrown from the C++ code. Hardware traps, like an access violation, are not caught.
If you don't want new
to throw either, you can use new(std::nothrow) int[10];
Some systems won't let you catch null reference exceptions at all, so relying on handling for them is a bad idea. Particularly in a situation where you can simply do a check. Your foo
function should look something like this:
int foo(int** arrayPtr)
{
// If a valid pointer has been passed in...
if(arrayPtr) {
// update the pointer to point at the allocated memory.
*arrayPtr = new int[10];
return 0;
}
return 1;
}
A better approach would be to pass the pointer in by reference. That way there's no way that a NULL
pointer pointer can be passed in and your problem effectively goes away.
// Pass in a reference to an array pointer. The reference can't be NULL...
int foo(int* &arrayPtr)
{
// update the reference
arrayPtr = new int[10];
return 0;
}
Your calling code then becomes:
int* myArray;
int ret;
ret = foo(myArray); // Pass in by reference
I think it's also worth pointing out that with your original code, even if it had worked as you expected your catch block would have been leaking the allocated array, since you weren't cleaning it up:
int foo(int** arrayPtr)
{
int* array = new int[10];
try {
*arrayPtr = array;
}
catch(...)
{
// EVEN IF THIS HAD WORKED AS INTENDED, YOU LEAK array BECAUSE IT'S NOT DELETED
// delete array; // is missing
return 1;
}
return 0;
}