【问题标题】:Does returning a dynamically-allocated array from a function cause a memory leak?从函数返回动态分配的数组会导致内存泄漏吗?
【发布时间】:2013-02-18 07:50:14
【问题描述】:

我问这个问题是为了让自己摆脱对以下程序的困惑。我知道在某些上下文中使用数组会使数组衰减为指向其第一个元素的单个指针。我有一个通过指针返回这个数组的函数(这个函数是使用new[] 创建的)。数组会衰减,导致指针仅指向第一个元素吗?这是一个例子:

int *foo() {
    int *t = new int[10];

    return t;
}

int main() {
    int *p = foo();
}

这就是混乱的地方。我不知道p 是指向第一个元素还是指向整个数组。所以我有以下问题:

  • 通过指针返回数组是否会导致数组衰减(进而导致内存泄漏)?
  • p 是否指向数组的第一个元素?
  • 如果以上两个为真,在p 上使用delete[] 会导致未定义的行为吗?

我希望这些问题能够得到解答,以便我能够完全理解这个程序。谢谢。

【问题讨论】:

  • 如果你的下一行是p = '' 或其他东西,你会“丢失”从 foo 返回的指针,并且繁荣......内存泄漏。如果您忽略清理分配的任何内存,这只是内存泄漏。其中一部分可能是“忘记”或“丢失”指向该内存的指针。
  • "decay" 对使用动态存储持续时间创建的对象根本不做任何事情。它只是描述了数组表达式发生的事情,将它们视为指针类型。
  • 内存泄漏不是关于如何在应用程序中传递指针,而是关于如何确保(“管理”)所有已分配的内存也被释放。内存管理越简单,代码中出现内存泄漏的可能性就越小~> 所以请尽可能关注RAII :)
  • 衰减只影响数组类型的变量。你没有这样的东西。

标签: c++


【解决方案1】:

通过指针返回数组是否会导致它的衰减(并因此导致内存泄漏)?

您实际上返回了t 的副本,它是一个指针。它已经指向动态分配数组的第一个元素。只有调用delete [] 失败才会有内存泄漏。

p 是否指向数组的第一个元素?

是的

如果以上两个为真,对 p 使用 delete[] 会导致未定义的行为吗?

不,这样做很好。只要函数返回一个指向动态分配数组的指针。

你已经发现了这个习惯用法的一个严重问题:你不知道你得到的是一个指向一个元素的指针,一个指向动态分配数组的第一个元素的指针,还是一个指向全局的指针。通过查看函数的返回类型,您无法知道是否需要调用deletedelete [],或者根本不调用delete。解决方案:不要返回指针!返回一个更好地表达正在发生的事情的类型,并且负责管理自己的资源(std::vectorstd::arraystd::unique_ptrstd::shared_ptr...)。

【讨论】:

    【解决方案2】:

    您的函数分配内存并返回一个指向它的指针,或者更专业地说,指向您正确认识的第一个元素。

    之后内存会发生什么取决于调用者。这意味着当返回的数组不再使用时,调用者应该使用 delete[] 将其删除。如果调用者不遵守这条规则,程序就会泄漏内存。如果你写这样的代码,你应该在你的方法的文档中强烈强调这一点!

    更现代的解决方案是使用智能指针。智能指针本身就是保护底层指针的对象(不是指向对象的指针)。根据我们在这里讨论的智能指针的类型,它会在调用者超出范围时自动删除(它唯一地持有分配内存的所有权),或者当它不再被其他人使用(共享所有权)时.

    详情请看这个问题:smart pointers and arrays

    现在,如果函数的编写方式与您的问题一样,因此它返回的是原始指针而不是智能指针,您仍然可以通过在之后包装数组来利用调用者中智能指针的功能。

    关于元素个数/要删除的内存量,这完全取决于delete[]的实现,所以你不必担心调用者的元素个数。但是,您也不能查询要使用它们的元素的数量。如果您需要元素的数量,您也必须返回它们,可能通过“out 参数”。

    在现代 C++ 中,我强烈建议使用不同于原始数组的数据结构,例如 std::vector,或者如果您需要 关联 容器,则使用 std::map,以及诸如“谁删除了这个分配的内存?”之类的问题。没了。

    【讨论】:

      【解决方案3】:

      如果以上两个是在 p 上使用 delete[] 会导致未定义的行为 真的吗?

      不,不删除[] p 会导致内存泄漏!

      然而,delete[] 神奇地知道数组有多长,sizeof(p) 不知道, 因为分配器会跟踪分配的空间。然而 sizeof 是编译时生成的固定值

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-18
        • 2012-08-10
        • 2012-12-23
        相关资源
        最近更新 更多