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

Prevent C++ DLL exception using try catch internally

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

1
2
3
4
5
int foo(int** arrayPtr) {
  int* array = new int[10];
  *arrayPtr = array;
  return 0;
}

所以,我主要是这样调用函数:

1
2
3
int* myArray;
int ret;
ret = foo(&myArray);

现在,myarray指向新创建的数组。

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

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

1
*arrayPtr = array;

将尝试写入0x00000。

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

1
2
3
4
5
6
7
8
9
int foo(int** arrayPtr) {
  int* array = new int[10];
  try {
    *arrayPtr = array;
  } catch(...) {
    return 1;
  }
  return 0;
}

我希望,当我使用空值作为参数调用foo时,它将返回1。不是真的!它生成一个异常。

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

谢谢大家!

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


  • 这几乎就是做到这一点的方法。只需确保公开一个函数来删除调用"foo"分配的内存块(以防您的dll使用不同于主应用程序的crt)。

  • 访问违反不应该抛出C++异常,尽管在VC++中有一些设置会使SEH异常映射到C++中,这通常被认为是一个坏主意。


  • 假设您使用的是VC++,那么默认情况下,try..catch不会捕获访问冲突,因为默认的异常处理模型只捕获同步异常,而访问冲突是异步异常。这里记录了这一点:/eh(异常处理模型)

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

    这就是说,为什么不明确检查一下NULL?为流控制使用异常是错误的形式。

    1
    2
    3
    4
    5
    6
    int foo(int** arrayPtr) {
        if (!arrayPtr)
            return 1;
        *arrayPtr = new int[10];
        return 0;
    }


  • 另一个选项是返回指针而不是代码。为失败的分配返回空值似乎非常明显。
  • 将空值传递给函数更像是调用端的错误。以不合理的访问冲突终止程序。这将向来电者显示他的错误所在!

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

    如果你不想让new投球,你可以用new(std::nothrow) int[10];投球。


    有些系统根本不允许捕获空引用异常,因此依赖于对它们的处理是一个坏主意。尤其是在你可以简单地检查的情况下。您的foo函数应该如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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指针指针,从而有效地消除问题。

    1
    2
    3
    4
    5
    6
    7
    // 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;
    }

    然后您的呼叫代码变为:

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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;
    }


    质疑1:我看不出这个功能有什么问题。你能用"更好"来定义你的意思吗?您可以将std::shared_ptr与数组类型一起使用,或者使用boost::shared_数组来更好地处理资源。但这取决于您想要使用的接口。

    质疑2:

    1
    2
    3
    4
    5
    try {
        *arrayPtr = array;
      } catch(...) {
        return 1;
      }

    当arraypter为空时,这将创建一个访问冲突。不能用C++尝试/ catch块来捕获这些。