有没有办法解除分配在堆栈上创建的变量和/或对象?我特别谈论堆栈而不是堆。
我不想辩论这是否有用或是好的做法,我只需要知道它是否可行。
我知道当它超出范围时会自动解除分配。我想在它超出范围之前解除分配。
我正在使用C ++。
答案 0 :(得分:10)
{
int a;
} // 'a' "deallocated" here
在封闭范围结束之前,你无法摆脱a
。
答案 1 :(得分:4)
每次从函数返回时,该函数在堆栈上分配的任何内存都将被释放。如果由于某种原因需要缩小变量范围,可以通过创建{}
的块来创建一个新的较小范围。
void function(void)
{
int x;
{
int y;
} // scope of y ends
} // scope of x ends
答案 2 :(得分:3)
您不能过早地结束“自动”对象的生命周期,但您可以随时终止动态对象的生命周期。可以在堆栈上创建一个动态对象,就像一个自动变量一样,但是它很复杂。
#include <new>
#include <string>
int main() {
typedef std::aligned_storage<sizeof(std::string)> stringbuffer;
stringbuffer buff;
std::string& str =*new(buff)std::string("banana"); //str alive on stack
std::cout << str;
str.~std::string(); // str is destroyed. DO NOT FORGET
std::cout << '\n';
}
这很容易出错,当然,boost has code for this。
int main() {
boost::optional<std::string> str;
str = "banana"; //str is alive on the stack
std::cout << str;
str = boost::none; //str is destroyed. Ok to forget
std::cout << '\n';
}
这两个都避免了FredOverflow的答案的潜在UB,因为如果在对象不活动时抛出异常,则不会在死对象上自动调用析构函数。
Azza指出,这确实不取消分配空间,它只是破坏了。早期解除空间是不可能的。
答案 3 :(得分:2)
当堆栈变量超出范围时,它们将被释放。就是这样。
答案 4 :(得分:1)
不,在移动范围超出可移植C ++范围之前,无法解除分配堆栈变量。
使用这样的内联汇编可以做一些延迟和不可移植的事情(示例仅使用 使用x86,仅使用Visual Studio):
int* ptr;
__asm {
sub esp, sizeof(int) // allocate variable
mov [esp + sizeof(int)], esp // move its address into ptr
}
*ptr = 4; // assign 4 to the variable
cout << *ptr << endl; // print variable
__asm {
add esp, sizeof(int) // deallocate variable
}
但是,不要指出太多问题。
答案 5 :(得分:1)
这个问题毫无意义。通常,在创建线程时,会在进程堆上分配线程堆栈(内存保留和部分提交)。当线程(通常)退出时进行处理。它在运行时具有固定的最大大小(保留内存),并通过从保留池提交更多内存来“增长”。当函数调用使用堆栈时,没有实际的内存分配 - 堆栈空间函数使用(对于其局部变量)是预分配和已提交内存的区域。你无法取消分配它。
想象一下,你在地址addr
的堆上分配了100个字节,将指针传递给addr+0x40
并调整大小0x10
以使其在内部使用。函数可以在此地址创建一些变量(对象),总大小不超过16个字节,例如使用placement new
。它可以(通常应该)通过显式调用析构函数来销毁对象。但它没有业务解除分配任何内存 - 传递给它的指针甚至没有指向分配区域的开头......而且非常简化,堆栈如何工作 - 函数获取其局部变量的预分配内存的一部分,它在这个内存中调用构造函数,然后在退出时调用析构函数。但它不会分配或释放任何堆栈空间。尝试这样做会导致访问冲突(分段错误)。