使用try catch在内部防止C ++ DLL异常

时间:2011-05-10 14:52:24

标签: c++ exception dll try-catch

我正在开发一个为主应用程序分配数组的C ++ DLL。 该函数返回错误代码而不是指向新创建的数组的指针,因此第一个成员的地址将写入函数的参数中。 例如:

int foo(int** arrayPtr) {
  int* array = new int[10];
  *arrayPtr = array;
  return 0;
}

所以,在主要方面我用这种方式调用函数:

int* myArray;
int ret;
ret = foo(&myArray);

现在myArray指向新创建的数组。

问题1:有更好的方法吗?

比更有趣的问题。 如果我将NULL作为foo的参数传递,我会生成一个访问冲突异常,因为

*arrayPtr = array;

将尝试写入0x00000。

所以,我添加了一个try-catch块

int foo(int** arrayPtr) {
  int* array = new int[10];
  try {
    *arrayPtr = array;
  } catch(...) {
    return 1;
  }
  return 0;
}

我希望,当我以NULL作为参数调用foo时,它将返回1.不正确!它会产生异常。

问题2:为什么DLL中的try-catch块不起作用?

感谢大家!

P.S。:使用try-catch直接在main中生成相同的异常不会产生异常(或者更好,它由try-catch块正确处理)。

5 个答案:

答案 0 :(得分:1)

假设您正在使用VC ++,try..catch默认情况下不会捕获访问冲突,因为默认的异常处理模型仅捕获同步异常,并且访问冲突是异步< / em>例外。这在此处记录:/EH (Exception Handling Model)

如果您将项目设置更改为使用/EHa而不是/EHsc,那么您的try..catch将会遇到访问冲突。

那说,为什么不明确检查NULL?使用流控制的例外是错误形式。

int foo(int** arrayPtr) {
    if (!arrayPtr)
        return 1;
    *arrayPtr = new int[10];
    return 0;
}

答案 1 :(得分:1)

  1. 这几乎就是这样做的。只需确保公开一个函数来删除通过调用“foo”分配的内存块(以防你的dll使用与主应用程序不同的CRT)。

  2. 访问冲突不应该抛出C ++异常,尽管VC ++中有一些设置可以将SEH异常映射到C ++异常,这通常被认为是个坏主意。

    < / LI>

答案 2 :(得分:0)

问题1:
我没有看到这个功能有什么不好。你能更好地定义你的意思吗? 您可以将std :: shared_ptr与数组类型或boost :: shared_array一起使用以获得更好的资源处理。但这取决于您要使用的界面。

问题2:

try {
    *arrayPtr = array;
  } catch(...) {
    return 1;
  }

当arrayPtr为NULL时,这将创建访问冲突。你无法用c ++ try / catch块来捕获它们。

答案 3 :(得分:0)

有些系统根本不会让你捕获空引用异常,所以依赖于处理它们是一个坏主意。特别是在您可以简单地进行检查的情况下。您的foo函数应如下所示:

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

更好的方法是通过引用传递指针。这样就无法传入NULL指针指针,你的问题就会有效消失。

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

您的主叫代码将变为:

int* myArray; 
int ret; 
ret = foo(myArray); // Pass in by reference

我认为值得指出的是,使用原始代码,即使它按预期工作,你的catch块也会泄漏分配的数组,因为你没有清理它:

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

答案 4 :(得分:0)

  1. 另一种选择是返回指针而不是代码。为失败的分配返回NULL似乎非常明显。
  2. 2a上。将NULL传递给您的函数似乎更像是调用端的错误。使用访问冲突终止程序并非不合理。这将向调用者显示他的错误!

    2B。 catch子句只能捕获从C ++代码抛出的异常。硬件陷阱(如访问冲突)不会被捕获。

    如果您不希望new投掷任何一个,可以使用new(std::nothrow) int[10];