0

为文件操作编写一个 dll,我遇到了一些问题。

要通过 file.read 从文件中读取字节,我需要一个所需长度的 char* 数组。由于长度是可变的,我不能使用

char* ret_chars[next_bytes];

它给出了 next_bytes 不是常量的错误。

StackOverflow 中的另一个主题说要使用:

char* ret_chars = new char[next_bytes];

据我所知,使用“new”创建它需要稍后使用“delete”。

现在,如果这个函数的返回值应该正是这个数组,我应该如何删除数组?如果我不在任何地方使用“删除”,这不是内存泄漏吗?

如果这有任何帮助:这是我将从“Game Maker”调用的 DLL。因此,我以后无法删除任何内容。

希望可以有人帮帮我!

4

7 回答 7

4

当您编写将由现有代码调用的回调时,您必须遵循其规则。

假设“Game Maker”的作者不是完全白痴,他们会释放你返回的内存。所以你必须检查文档以找出他们将使用什么函数来释放内存,然后你必须调用匹配的分配器。

在这些情况下,框架通常会提供一个专门为您设计的分配函数,用于分配返回缓冲区。

另一种常见的方法是您永远不会返回由回调分配的缓冲区。取而代之的是,框架将缓冲区传递给您的回调,您只需将其填入即可。请查看文档以了解这种可能性。

是否没有编写“Game Maker”插件/扩展的示例代码?


看起来开发人员确实是彻头彻尾的白痴,至少在插件接口设计方面是这样,但他们确实提供了一些指导

请注意,您必须小心内存管理。这就是为什么我将生成的字符串声明为全局的。

这意味着 Game Maker 引擎不会尝试释放返回的缓冲区。

您也可以使用全局变量,或者实际上任何具有静态存储持续时间的变量,例如函数局部静态变量。 std::vector<char>将是一个不错的选择,因为它很容易调整大小。这样,每次调用函数时,分配给前一次调用的内存都会被重用或释放。因此,您的“泄漏”将仅限于您一次返回的金额。

char* somefunc( void )
{
    static std::vector<char> ret_buffer;

    ret_buffer.resize(next_bytes);
    // fill it in, blah blah
    return &ret_buffer[0];
}
// std::string and return ret_string.c_str(); is another reasonable option

您的 Game Maker Language 脚本将负责在再次调用您的函数并覆盖它之前制作该结果字符串的副本。

于 2013-07-16T16:29:26.483 回答
1

使用vector <char *>(或vector <char>取决于你真正想要的 - 问题并不完全清楚),这样你就不需要删除任何东西。

您不能new在函数内部使用,而不调用 delete,否则您的应用程序将泄漏内存(这是一件坏事,因为最终,您将没有内存可用)。对此没有简单的解决方案,在某种程度上没有一些相对严格的限制。

于 2013-07-16T16:18:30.210 回答
1

这个new char[ n ]技巧适用于运行时值,是的 - 当你完成它或它泄漏时,你需要删除 [] 数组。

如果您无法更改“Game Maker”(无论是什么)的工作方式,那么内存将会泄漏。

如果您可以更改“Game Maker”来做正确的事情,那么必须管理返回数组的生命周期。

这才是真正的问题——DLL代码不知道什么时候不再需要它,所以调用代码需要在完成后删除它,但调用代码不能直接删除它——它必须回调DLL才能删除它,因为首先分配它的是 DLL 的内存管理器。

由于您说返回值必须是 char[],因此您需要从 DLL 中导出第二个函数,该函数采用 char[],并在其上调用 delete[]。调用代码可以在完成之前返回的数组后调用该函数。

于 2013-07-16T16:18:14.713 回答
0

好的,我也来顶一下。

如果 Game Maker 没有明确表示它将删除此内存,那么您应该检查它想要多大的缓冲区,并改为传递该大小的静态缓冲区。这避免了与内存管理的交叉 dll 版本控制问题相关的各种麻烦。他们的代码或 API 中必须有一些关于此的文档,我强烈建议您找到并阅读它。Game Maker 是一个相当大且广为人知的 API,因此如果您自己没有文档,Google 应该会为您提供信息。

于 2013-07-16T17:17:39.440 回答
0

首先,如果你使用new char[];你不能使用delete,但你必须使用delete []

但是就像你说的,如果你new []在这个函数中使用而不delete []在最后使用你的程序将会泄漏。

如果你想要一种垃圾回收,你可以使用标准 c++ 库中的 *​​smart ptr*。我认为 `shared_ptr` 会很好地实现你想要的。> **Shared ptr** :管理指针的存储,提供有限的垃圾收集设施,可能与其他对象共享该管理。这是一些关于它的文档:http://www.cplusplus.com/reference/memory/shared_ptr/
于 2013-07-16T16:20:50.847 回答
0

您引用的第一个代码示例在堆栈上分配内存。您引用的第二个代码示例在堆上分配内存。(两个完全不同的概念)。

如果要返回数组,则分配内存的函数不会释放它。由调用者来删除内存。如果调用者忘记了,那么是的,这是内存泄漏。

于 2013-07-16T16:20:55.010 回答
0

如果您要返回一个 char 指针,看起来就像是,那么您可以简单地对该指针调用 delete。

例子:

char * getString()
{
    char* ret_chars = new char[next_bytes];
    strcpy(ret_chars, "Hello world")
    return ret_chars
}

void displayChars()
{
    char* chars = getString()
    cout << chars
    delete [] chars
}

只要确保释放(删除)所有已分配(新的)指针,否则您将在分配内存的地方出现内存泄漏,然后在运行后不收集并变得不可用。一种快速而肮脏的方式来浏览并查看您是否已释放所有分配的空间以计算新空间并计算删除数量,除非某些出现在条件或循环块中,否则它们应该是一对一的。

于 2013-07-16T16:22:00.510 回答