返回指针(数组)时可能存在内存泄漏(C++)

4

考虑以下C++代码片段:

int *foo() {
    int *y = new int[1000];
    return y;
}

int main() {
    int *x = new int [1000];
    x = foo();
    delete[] x;
    return 0;
}

当创建变量 x 时,它会指向一个内存地址。当调用函数 foo() 时,会创建一个新的指针 y,它指向另一个地址,但是变量 x 的值被设置为 y 的地址。因此,当删除 y 时,新地址的内存被释放,但是原始地址的内存泄漏了。这样说对吗?
此外,我稍微修改了代码片段,在调用 foo() 之前调用了 delete[] x,但仍然可以编译和运行:
int *foo() {
    int *y = new int[1000];
    return y;
}

int main() {
    int *x = new int [1000];
    delete[] x;
    x = foo();
    delete[] x;
    return 0;
}

这是否意味着我已经防止了内存泄漏?最后一个问题,如果我在声明变量 x 时没有初始化它,但没有过早地删除它,那么它是否指向将会泄漏的内存?就像下面这样:

int *foo() {
    int *y = new int[1000];
    return y;
}

int main() {
    int *x;
    x = foo();
    delete[] x;
    return 0;
}

作为一种旁注,我知道使用向量和/或唯一指针更安全,但我对上面的代码功能很好奇,特别是在声明但稍后初始化指针时会发生什么。

问题表述清晰,谢谢! - Lightness Races in Orbit
2个回答

4
当 x 被创建时,它指向一个内存地址。当调用 foo() 时,会创建一个新的指针 y ,它指向另一个地址,但是接着 x 被设置为 y 所有的地址。因此,当释放这个变量时,新地址所占据的内存会被释放,但是原先 x 指向的地址就泄漏了。这样理解对吗?
是的。
那我现在已经避免了泄漏吗?
是的。
最后一个问题,如果我在声明 x 的时候没有初始化它,但没有过早地删除它,那么它指向的内存会泄漏吗?
不会。
另外一件事情,使用 vector 和/或 unique pointer 更加安全。
绝对没错。即使没有这些,你的代码也应该更清晰关于内存所有权,这样你的问题就不会出现,但是使用标准容器/智能指针可以从根本上解决这个问题,我强烈推荐这样做。
简而言之,你之前的理解都是正确的。

1
据我理解,未初始化的指针实际上还没有指向任何位置。 - Daniel
1
@Daniel 指针总是指向某个地方。未初始化的指针指向某个地方,但它并不指向任何安全可用的东西。在现代系统中,它通常指向即时死亡,而 Grim Garbage Collector 很乐意收割。但有时它会指向已分配给程序的内存,这些可能是绝对难以找到和调试的 <删除的粗话>。代码 在这里 与代码 在那里 毫无关系,只是把 在那里 的内存弄烂了,当程序在 那里 出错时,你可能不会从调试代码 在这里 开始。 - user4581301
@Daniel 正确的。 - Lightness Races in Orbit
1
@user4581301 "指针指向某处。未初始化的指针指向某个地方,但它并不指向任何安全可用的东西" 这是一个语义问题。很容易争论未初始化的指针确实没有“指向某处”,因为在没有UB(其值是未指定的)的情况下不能观察其值。实际上,它具有一些任意的数字值,您可以将其描述为“可能不安全的指向某处”,但这不是语言的看法,也不应该是您的看法。 - Lightness Races in Orbit

0
在你上面的代码片段中:
int *x = new int [1000];
x = foo();
delete[] x;

您将一个数组指针分配给了x,但是又通过将foo()赋值给它来"压缩"了它。如果您使用垃圾回收语言(或者使用智能指针),那么在这种情况下内存将被回收。

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