【问题标题】:"New" and "delete" in a function函数中的“新建”和“删除”
【发布时间】:2015-07-13 03:56:59
【问题描述】:

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

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

char* ret_chars[next_bytes];

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

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

char* ret_chars = new char[next_bytes];

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

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

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

希望有人可以帮助我!

【问题讨论】:

  • Game Maker 之后会如何处理内存?
  • 我不知道:/
  • 我可以使用 DLL 的初始化和退出函数来代替吗?
  • 查看我的更新答案。

标签: c++ dll new-operator delete-operator


【解决方案1】:

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

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

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

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

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


看起来开发者确实是彻头彻尾的白痴,至少在插件接口设计方面,但他们确实提供了some guidance

请注意,您必须小心内存管理。这就是我将结果字符串声明为全局的原因。

这意味着 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 脚本将负责在再次调用您的函数并覆盖它之前制作该结果字符串的副本。

【讨论】:

  • Game Maker 不是另一个 C++ 库,而是一个游戏开发工具(具有自己的语言),它允许调用 DLL 以扩展其功能。事情是我不知道它是否会自动删除 char*。
  • @DragonGamer:我几乎可以向你保证,它不会使用你的 C++ 版本的delete[],它与new[] 匹配。但它应该使用一些释放功能。
  • 好的,谢谢!但是我必须为“矢量”包括什么?现在如何通过 .read 从 fstream 将字节填充到该数组中?该函数需要一个 char* 数组。
  • @DragonGamer: #include &lt;vector&gt;,你可以做stream.read(&amp;ret_buffer[0], next_bytes),因为矢量内容是连续的
  • @BenVoigt:另一种可能性是您分配内存,进行调用,它复制内存,然后在函数之后释放您自己的内存。有点像 const char*std::string 构造函数。
【解决方案2】:

new char[ n ] 技巧适用于运行时值,是的 - 您需要在使用完数组后删除 [] 数组,否则它会泄漏。

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

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

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

因为你说返回值必须是一个char[],所以你需要从你的DLL中导出第二个函数,它接受char[],并在它上面调用delete[]。调用代码可以在完成之前返回的数组后调用该函数。

【讨论】:

  • “新的 char[n] 技巧” - 这不是技巧,它是分配动态内存的标准方法。
  • @icepack:仅从源代码角度来看是“标准”。与该分配相关的元数据绝不是标准的,因此您不能将一个 DLL/编译器/库版本中的 new char[n] 与另一个中的 delete[] 混合。
【解决方案3】:

使用vector &lt;char *&gt;(或vector &lt;char&gt;,具体取决于您真正想要的-问题并不完全清楚),这样您就不需要删除任何内容。

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

【讨论】:

  • 不考虑他要返回数组的事实。
  • 要放入向量中的指针来自哪里?你的意思是std::vector&lt;char&gt;?这不会让他向调用者返回任何东西,因为内存已经消失,在他的函数返回之前自动清理。
  • OP 帖子的第一行:char* ret_chars[next_bytes];
  • 下一行,char* ret_chars = new char[next_bytes]; 这个问题有点令人困惑,但从问题的其余部分来看,他似乎通过char* 返回了char 的数组,而不是@ 的数组987654328@.
  • 这个函数是调用一次还是多次,你应该每次返回相同的字符串,还是不同的字符串。
【解决方案4】:

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

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

【讨论】:

    【解决方案5】:

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

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

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

    【讨论】:

    • 实际上,shared_ptr 对于跨 DLL 边界传递缓冲区很糟糕
    • @BenVoigt 即使我同意你的论点,它也可以成为一个解决方案。但它是解决方案之一。如果没有,他必须要求开发人员(在函数文档中)使用他的 DLL 在使用此函数后释放内存...
    • 其他模块也不能使用delete[]。这些是其他语言不知道的 C++ 特性,甚至不兼容不同的编译器版本。
    【解决方案6】:

    好的,我也加入。

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

    【讨论】:

      【解决方案7】:

      如果您要返回一个 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
      }
      

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

      【讨论】:

      • 你必须使用 delete[]
      • 这是我的想法,但就像我说的,Game Maker(这是一款仅使用脚本语言开发的游戏--> 没有内存操作)不允许我直接删除字符*..
      • 哦,我没有意识到这一点,我的错。这个工具可以让你使用新建而不是删除?这很奇怪:/
      • @jon.kerlinger:不是工具不允许他使用delete(或delete[]),而是返回已经删除的内存不是一个好主意。
      猜你喜欢
      • 2011-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-17
      • 2015-06-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多