5

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

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

    return t;
}

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

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

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

我希望可以回答这些问题,以便我可以完全理解这个程序。谢谢你。

4

3 回答 3

7

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

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

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

是的

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

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

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

于 2013-02-17T23:34:35.680 回答
6

您的函数分配内存并返回指向它的指针,或者从技术上讲,返回您正确知道的第一个元素。

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

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

有关详细信息,请参阅此问题:智能指针和数组

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

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

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

于 2013-02-17T23:35:30.127 回答
0

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

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

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

于 2013-02-17T23:37:14.863 回答