预防 C++内部使用 try catch 的 DLL 异常

发布于 2024-11-06 08:56:52 字数 852 浏览 0 评论 0原文

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

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

因此,在 main 中我这样调用该函数:

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 块不起作用?

谢谢大家!

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

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).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

半夏半凉 2024-11-13 08:56:52

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

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

也就是说,为什么不显式检查 NULL 呢?使用异常进行流量控制是不好的形式。

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

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;
}
橪书 2024-11-13 08:56:52
  1. 这几乎就是做到这一点的方法。只需确保公开一个函数来删除通过调用“foo”分配的内存块(以防万一您的 dll 使用与主应用程序不同的 CRT)。

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

  1. That's pretty much the way to do it. Just be sure to expose a function to delete the memory block allocated by calls to "foo" (just in case your dll uses a different CRT than the main app).

  2. Access violations are not supposed to throw C++ exceptions, although there is some setting in VC++ that would make a SEH exception to be mapped to a C++ one, which is generally considered a bad idea.

万人眼中万个我 2024-11-13 08:56:52

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

对于问题 2:

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

当 arrayPtr 为 NULL 时,这将导致访问冲突。您无法使用 C++ try/catch 块捕获这些内容。

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.

扶醉桌前 2024-11-13 08:56:52
  1. 另一种选择是返回指针而不是代码。分配失败时返回 NULL 似乎是很明显的。

2a.将 NULL 传递给函数似乎更像是调用方的错误。由于访问冲突而终止程序并非不合理。这将向调用者显示他的错误在哪里!

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

如果您不想 new 抛出任何一个,您可以使用 new(std::nothrot) int[10];

  1. 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];

凯凯我们等你回来 2024-11-13 08:56:52

有些系统根本不允许您捕获空引用异常,因此依赖于它们的处理是一个坏主意。特别是在您可以简单地进行检查的情况下。您的 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; 
} 

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; 
} 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文