堆栈销毁期间自动清理堆

Automatic heap cleanup during stack destruction

本文关键字:堆栈      更新时间:2023-10-16
int* f()
{
    int *p = new int[10];
    return p;
}
int main()
{
    int *p = f();
    //using p;
    return 0;
}

在堆栈销毁期间,当函数返回它的值时,某些编译器(当我被告知时暗示了 VS 或 gcc 等常见编译器(是否可以尝试自动释放本地指针(如本例中的 p(指向的内存?即使不是,我是否可以正常删除 main 中分配的内存?问题似乎是此时丢失了有关确切数组大小的信息。另外,在malloc和free的情况下,答案会改变吗?

谢谢。

只有局部变量被销毁释放。

在您的情况下,p被"销毁"(释放(,但p所指向的不是"销毁"(使用 delete[] 释放(。

是的,您可以,并且应该/必须在您的主上使用delete[]。但这并不意味着在C++中使用原始指针。您可能会发现这本电子书很有趣: 链接-阿尔夫-书

如果您想delete函数"结束"(超出范围(时局部变量指向的内容,请使用std::auto_ptr()(仅适用于非数组变量,不适用于需要delete[]的变量(

另外,如果情况,答案会改变吗 的马洛克和自由?

不,但你应该确保你不要混合free()/new/delete/malloc().这同样适用于new/delete[]new[]/delete

不,它们不会freedelete你的指针指向什么。它们只会释放指针本身占用的几个字节。我认为,调用freedelete的编译器会违反语言标准。

只有当你有一个指向内存的指针,即来自f()的结果,你才能main delete[]内存。您不需要跟踪分配的大小; newmalloc幕后为你做这件事。

如果要在函数返回时清理内存,请使用智能指针,例如 boost::scoped_ptrboost::scoped_array(均来自库的 Boost 集合(、std::auto_ptr(在当前C++标准中,但即将被弃用(或std::unique_ptr(在即将推出的标准中(。

在 C 语言中,不可能创建智能指针。

在堆栈销毁期间,当函数返回它的值时,某些编译器(当我被告知时暗示了 VS 或 gcc 等常见编译器(是否可以尝试自动释放本地指针(如本例中的 p(指向的内存?

简短回答:否

长答案:

如果您使用的是智能指针或容器(就像您应该的那样(,那么是的。
当智能指针超出范围时,内存将释放。

std::auto_ptr<int> f()
{
    int *p = new int;
    return p; // smart pointer credated here and returned.
              // p should probably have been a smart pointer to start with
              // But feeling lazy this morning.
}
std::vector<int> f1()
{
    // If you want to allocate an array use a std::vector (or std::array from C++0x)
    return std::vector<int>(10);
}
int main()
{
    std::auto_ptr<int> p = f();
    std::vector<int>   p1 = f1();
    //using p;
    return 0;  // p destroyed
}

即使不是,我是否可以正常删除 main 中分配的内存?

确保在不需要时立即正确释放所有内存是正常的。
请注意delete []delete是不同的,因此在使用它们时要小心。

分配了new的内存必须与 delete 一起释放。
分配了new []的内存必须与 delete [] 一起释放。
分配了malloc/calloc/realloc的内存必须与 free 一起释放。

问题似乎是此时丢失了有关确切数组大小的信息。

记住此信息是运行时系统的问题。它的存储方式没有由标准指定,但通常它接近分配的对象。

另外,在malloc和free的情况下,答案会改变吗?

在C++你可能不应该使用malloc/free。但它们可以使用。使用它们时,应将它们一起使用,以确保内存不会泄漏。

您被误导了 - 局部变量被清理,但分配给局部指针的内存没有。如果不返回指针,则会立即出现内存泄漏。

不要担心编译器如何跟踪分配了多少元素,这是C++标准未解决的实现细节。只要知道它有效。(只要你使用delete[]表示法,你做到了(

当您使用new[]时,编译器会添加额外的簿记信息,以便它知道要delete[]多少个元素。(以类似的方式,当您使用malloc时,它知道要free多少字节。一些编译器库提供扩展来找出该大小。

我还没有听说过编译器这样做,但编译器当然有可能检测(在许多情况下(从函数中分配的内存是否不再被指针引用,然后释放该内存。

但是,在您的情况下,内存不会丢失,因为您保留了一个指向它的指针,该指针是函数的返回值。

内存泄漏的一个非常常见的情况和此类功能的完美候选者是以下代码:

int *f()
{
    int *p = new int[10];
    // do something that doesn't pass p to external
    // functions or assign p to global data
    return p;
}
int main()
{
    while (1) {
      f();
    }
    return 0;
}

正如您所注意到的,指向已分配内存的指针丢失了,编译器可以绝对肯定地检测到这一点。