在C++中释放非动态内存
Getting free of non-dynamic memory in C++
C/C++中是否有一个函数可以去除非动态数据,类似于动态分配内存的函数free();
。
我尝试使用函数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]
我将在这里的高级答案集中添加一个初学者级别的答案,以防真正的新手偶然发现问题:
您不需要释放堆栈上的数据结构,—正如重复数据删除程序所指出的—也不允许这样做除某些特殊情况外,所有未动态分配的数据(例如通过new)都由编译器放置在堆栈上。堆栈是程序在运行时的一个内存部分,它随着每次函数调用而增长,并随着每次函数退出而收缩。它被划分为所谓的堆栈帧,提供函数的本地内存。在编译时,编译器会发现一个函数需要多少内存——在您的例子中,对于两个4字节的整数,这将是8字节(假设您正在编译到32位目标)——并生成指令,创建一个足够大的堆栈帧,以便在调用函数时所有局部变量都可以驻留在其中。不过,有一种方法可以告诉编译器,你只需要在函数内的有限时间内使用一个变量:Scopes,它是由大括号创建的,正如niklasfi所指出的那样。一个例子:
int foo() {
int outerScopeVariable = 5;
{
int innerScopeVariableA = 8;
}
{
int innerScopeVariableB = 20;
}
}
变量innerScopeVariableA
将只"存在"在它周围的大括号中。在高级上,这意味着你不能在声明它的{}
块之外的作用域中引用它,对于块末尾的类,调用对象的析构函数。在低级别上,编译器知道在块的末尾不再需要为innerScopeVariableA
保留的内存。因为它是堆栈内存,尽管它不能像释放动态内存那样释放它。请记住,堆栈内存只在函数结束时被丢弃。但它所能做的是将innerScopeVariableA
的内存重新用于innerScopeVariableB
。因此,对于foo
,一个优化编译器实际上只需要8字节的堆栈内存。
有关堆栈和堆(这是分配动态内存的地方)的更多信息,您可以看看这个问题:堆栈和堆是什么以及在哪里。可以在这里找到对堆栈的深入讨论: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;
}
看看二进制g++在堆栈上为foo保留了4136个字节,其中4096个字节对于一个包含1024个元素的整数数组是必需的(我为32位目标编译过)。这一点点额外的空间可能与内存对齐有关。您也可以通过打印内存地址来观察这种效果,下面是一个使用在线编译器的示例:http://codepad.org/r5S1hvtV。
始终使用与分配方法互补的解除分配方法
对于堆栈变量,这意味着退出块,甚至可能退出函数
否则,您将得到未定义的行为,因此一切都可能发生。
在您的示例中,free()
似乎要么是
- 接受堆栈指针并破坏堆栈和堆管理结构(可能导致后续的进一步破坏)
- 或者它检查传递的指针是否已经由相应的分配器返回,然后什么也不做
对于调试来说,嘈杂的崩溃或至少明显的不当行为是最好的,但不能保证。
您可以将代码放在括号{}
中。任何对象都位于堆栈上,直到周围的括号闭合为止。例如
int b;
{
int a;
} // a gets destroyed, b is still alive
正如重复数据删除程序所说,通常情况下,您不需要像编译器那样负责变量的销毁。
我不会手动调用析构函数,因为除非使用重载形式的运算符new()
构造对象,否则这是一种糟糕的做法,除非使用std::nothrow
重载。
去除堆栈内存的一个常见习惯用法(从技术上讲,这可以作为你问题的答案)是将其与默认构建的临时进行交换
MyType t1;
std::swap(t1, MyType());
第二行用临时实例交换实例,因此原始实例在该行被销毁。
现在,您仍然在堆栈中留下一个实例,因此有两种情况,这将具有的意义
- 您希望在该行调用
t1
的析构函数(就好像去掉堆栈对象一样) - 默认构造的类型要小得多,因此您希望清除并最小化
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 开放 CV 中的动态内存分配,用于视频处理
- 为什么类和 main() 函数中也有动态内存分配
- 在没有动态内存的世界中,我是否需要虚拟析构函数?
- c++ 动态内存 堆栈中的分配
- 给定特定内存地址的数组的动态内存分配
- 释放动态内存时C++错误
- 我刚刚了解了C++中的动态内存分配
- 无法删除布尔动态内存分配
- 有没有办法找到动态内存大小,比如大小?
- 我在 2D 数组的动态内存分配中遇到了一些奇怪的代码C++? 请解释一下这是什么?
- 具有对齐存储的动态内存分配
- 指向数组unique_ptr在调用 release() 后会自动释放动态内存,这是真的吗?
- 在cpp中使用boost-python的python代码是否进行动态内存分配
- 我应该在这个程序中使用静态内存分配还是动态内存分配
- C++ 模板函数中的动态内存分配
- 指向动态内存中结构中的变量时出现问题
- C++具有动态内存分配的 constexpr 函数
- 动态内存分配错误
- 按引用传递和动态内存分配之间的区别是什么