2014-04-12 130 views
1

在C/C++中是否有一个函数可以摆脱非动态数据,类似于动态分配内存的函数free();在C++中释放非动态内存

我尝试使用功能free(i);但是编译器报错:

invalid conversion from 'int' to 'void*' [-fpermissive] 

在下面的代码我用free(&i);,编译器没有报告错误,但也并没有释放内存。

#include<iostream> 
#include<stdlib.h> 

int main() 
{ 
    int i, n; 
    cin >> n; 
    for(i = 0; i < n; i++); 
    cout << i << endl; 
    free(&i); 
    cout << i << endl; 
    return 0; 
} 

对于输入15输出是:

15 
15 

Process returned 0 (0x0) execution time : 11.068 s 
Press any key to continue. 

而且我从编译器得到了一个警告:

warning: attempt to free a non-heap object 'i' [-Wfree-nonheap-object] 

回答

3

,我会在这里的情况下,于加初学者水平答案一整套先进的答案实际新手绊倒问题:

你并不需要释放栈和数据结构 - 正如Deduplicator指出 - 不允许你要么。除一些特殊情况外,所有未动态分配的数据(例如,通过新的数据)由编译器置于堆栈上。堆栈是运行时程序的内存部分,随着每个函数调用而增长,并随着每个函数出口收缩。它被分成所谓的堆栈帧,它们提供你的函数的本地存储器。在编译期间,编译器会发现函数需要多少内存 - 在你的例子中,对于两个4字节整数(假设你正在编译为一个32位目标)将会是8个字节),并且产生的指令为所有人创建足够大的栈帧局部变量驻留在函数被调用时。然而,有一种方式告诉编译器,你只需要一个变量在函数内部有限的时间内:Scopes,它是由大括号创建的 - 就像niklasfi指出的那样。举个例子:

int foo() { 
    int outerScopeVariable = 5; 
    { 
     int innerScopeVariableA = 8; 
    } 
    { 
     int innerScopeVariableB = 20; 
    } 
} 

变量innerScopeVariableA将在它周围的花括号只“活”。在较高的级别上,这意味着您不能在{}块以外的作用域中引用它,并且在块的末尾声明了类的对象的析构函数。在低级别上,编译器知道在块末尾为innerScopeVariableA保留的内存不再需要。因为它是堆栈内存,尽管它不能像释放动态内存那样释放它。请记住,堆栈内存仅在函数结束时被丢弃。但它可以做的是重用innerScopeVariableA的内存innerScopeVariableB。因此,对于foo,优化编译器实际上只能使用8个字节的堆栈内存。

有关堆栈和堆的更多信息(这是分配动态内存的地方),您可以看看这个问题:What and where are the stack and heap?。堆栈的更深入的讨论可以在这里找到:http://www.altdevblogaday.com/2011/12/14/c-c-low-level-curriculum-part-3-the-stack/


编辑:如果你把大的数据结构栈上实际上,你可以看到这个堆栈内存重用。运行以下代码编译g ++ 4.8.1您的输出是123987

#include <iostream> 
using namespace std; 

void foo() { 
    { 
     int a[1024]; 
     a[0] = 123987; 
    } 
    { 
     int b[1024]; 
     cout << b[0] << endl; 
    } 
} 

int main() { 
    foo(); 
    return 0; 
} 

寻找在二进制克++储量4136个字节的堆栈,该堆栈4096的所必需的一个整数数组具有1024种元素于foo(我已经编译为一个32位的目标)。多余的空间可能与内存对齐有关。您也可以通过打印内存地址来观察这种效果,下面是使用在线编译器的示例:http://codepad.org/r5S1hvtV

1

您可以直接附上您的代码在括号{}。任何对象都会驻留在堆栈上,直到周围的括号关闭。例如。

int b; 
{ 
int a; 
} // a gets destroyed, b is still alive 

由于Deduplicator指出,通常情况下,您不需要照顾变量的销毁,因为编译器会为您做这件事。

3

始终使用补充分配方法的解除分配方法。
对于堆栈变量,这意味着退出块,甚至可能是函数。
否则你会得到未定义的行为,所以一切都可能发生。

在您的例子,free()似乎任

  • 接受堆栈指针和腐败的栈和堆管理结构,潜在地导致进一步腐败的路线,
  • 或它检查是否传递的指针可能已经由相应的分配器返回,然后默默无闻。

对于调试,一个嘈杂的崩溃或至少明显的不当行为将是可取的,但不能保证。

1

我不会去手动调用析构函数,因为这是不好的做法,除非对象是使用重载形式的运算符new()构造的,除非使用std::nothrow重载。

一个常见成语摆脱堆栈内存(和technichally资格作为一个回答你的问题)是有违约互换它构建的临时

MyType t1; 
std::swap(t1, MyType()); 

第二行交换的实例与暂时的,所以原始实例在该行被破坏。现在

,你还是留在堆栈中的实例,以便有2个情况下,这将有一个意义

  • 你想要的t1析构函数在该行被称为(好像摆脱栈对象)
  • 默认的构造类型小得多,所以你要clear and minimize