从函数中返回一个动态分配的数组会导致内存泄漏吗?

5

我提出这个问题是为了解决我对以下程序的困惑。我知道在某些情况下使用数组会导致它衰变为指向其第一个元素的单个指针。我有一个通过指针返回此数组的函数(此函数使用new[]创建)。这个数组会衰变吗,导致指针只指向第一个元素?以下是一个例子:

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

    return t;
}

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

这里出现了混淆。我不知道p是指向第一个元素还是整个数组。所以我有以下问题:
  • 通过指针返回数组会导致它衰减(从而导致内存泄漏)吗?
  • p是否指向数组的第一个元素?
  • 如果上述两个问题是正确的,那么在p上使用delete[]是否会导致未定义行为?
我希望这些问题能够得到回答,以便我能彻底理解这个程序。谢谢。

1
如果你的下一行是 p = '' 或者其他什么,你就会“丢失”从 foo 返回的指针,然后...内存泄漏。只有当你忽略清理分配的任何内存时,才会出现内存泄漏。其中一部分可能是“遗忘”或“丢失”指向该内存的指针。 - Marc B
“decay” 对于使用动态存储期创建的对象没有任何作用。它只是描述了一些发生在数组表达式上的事情,将它们视为指针类型。 - aschepler
内存泄漏不是关于如何在应用程序中传递指针,而是关于如何确保(“管理”)已分配的所有内存都被释放。内存管理越简单,代码中出现内存泄漏的可能性就越小 ~> 因此尽可能遵循RAII :) - LihO
衰减只会影响数组类型的变量。你没有这样的东西。 - Kerrek SB
3个回答

7
通过指针返回数组会导致其衰减(并因此导致内存泄漏)吗?
您实际上是在返回指向`t`的副本,它是一个指针。它已经指向动态分配数组的第一个元素。只有在未调用`delete []`时才会出现内存泄漏。 p是否指向数组的第一个元素?
是的
如果以上两个是正确的,在p上使用delete []会导致未定义的行为吗?
不会,这样做是可以的。只要函数返回对动态分配数组的指针即可。
您已经确定了这种用法的严重问题:您无法知道自己是否正在获得指向元素的指针、指向动态分配数组的第一个元素的指针、全局变量的指针。您不能通过查看函数的返回类型来知道是否需要调用delete、delete[]或根本不需要调用delete。解决方案:不要返回指针!返回更好地表达正在发生的事情并负责管理自己资源的类型(std::vector、std::array、std::unique_ptr、std::shared_ptr...)。

6
你的函数分配内存并返回一个指针,或者更准确地说,返回第一个元素的指针,正如你正确所知。
之后内存的处理取决于调用者。这意味着当返回的数组不再使用时,应该由调用者使用delete[]删除它。如果调用者不遵守这个规则,程序将泄漏内存。如果你编写这样的代码,应该在方法的文档中强调这一点!
像这样的问题的更现代解决方案是使用智能指针。智能指针本身就是对象(而不是指向对象的指针),它们保护底层指针。根据我们在这里讨论的智能指针类型,在调用者中运行出作用域时(唯一持有分配的内存权利),或者当它不再被其他人使用时(共享所有权),它将自动删除。
有关详细信息,请参见此问题:智能指针和数组 现在,如果函数像你的问题中那样编写,返回原始指针而不是智能指针,你仍然可以在调用者中包装数组来利用智能指针的功能。
关于要删除的元素数量/内存量,这完全取决于delete[]的实现,因此您不必担心调用者中的元素数量。但是,您也无法查询要使用的元素数量。如果您需要元素数,则必须通过“输出参数”返回它们。
在现代C ++中,我强烈建议使用与原始数组不同的数据结构,例如std :: vector,或者如果需要关联容器,则使用std :: map,这样可以避免“谁删除了此分配的内存?”等问题。

0

如果上述两个条件成立,使用delete[] p会导致未定义的行为吗?

不会,不使用delete[] p会导致内存泄漏!

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接