【问题标题】:How to deallocate variables on the stack?如何释放堆栈上的变量?
【发布时间】:2012-02-20 01:11:12
【问题描述】:

有没有办法解除分配在堆栈上创建的变量和/或对象?我说的是堆栈而不是堆。

我不想争论这是否有用或好的做法,我只想知道这是否可能。

我知道它会在超出范围时自动解除分配。我想在它超出范围之前解除分配。

我正在使用 C++。

【问题讨论】:

  • “解除分配”到底是什么意思?
  • 在实践中对于具有微不足道的析构函数的对象没有用处,因为编译器会在幕后对其进行 mojo。
  • 不可能。现在你知道了,你可以继续你的生活了。
  • 听起来像the XY Problem的情况。
  • 为什么这个问题被否决了?这是一个合法的问题,并遵守本网站上的所有规则。

标签: c++ memory


【解决方案1】:
{
  int a;
} // 'a' "deallocated" here

在封闭范围结束之前,您无法摆脱 a

【讨论】:

  • 他特别说“我想在它超出范围之前解除分配。”
  • @Nic 在发布此答案时不在问题的文本中。
  • @Nic,但这是荒谬的。什么是不在范围内的已释放变量?
  • 转让所有权不会被视为解除分配,对吗?
  • @CarlNorum 一个不存在的变量。
【解决方案2】:

每次从函数返回时,该函数在堆栈上分配的所有内存都会被释放。如果您出于某种原因需要缩小变量的范围,您可以通过使用{} 创建一个块来创建一个新的更小的范围。

void function(void)
{
   int x;
   {
     int y;
   } // scope of y ends
} // scope of x ends

【讨论】:

  • 我需要在它超出范围之前解除分配。
  • @Farhad,你可能不知道。如果不解释为什么需要这样做,您不太可能得到更好的答案。
  • 抱歉,FredOverflow 提供了更全面的答案。
  • @Farhad,目前还不清楚你为什么想要更多的东西。请告诉我们为什么这个答案不适合您。
【解决方案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 指出,这不会释放空间,它只是破坏。提前释放空间是不可能的。

【讨论】:

    【解决方案4】:

    堆栈变量在超出范围时被释放。就是这样。

    【讨论】:

    • 我知道,我需要在它超出范围之前解除分配。
    • @Farhad - 为什么?这是唯一有意义的概念性事物。如果需要,您可以通过使用{} 创建一个新块来为您的变量创建一个更小的范围。
    • 不正确。 void foo(void) { int a; bar(); } 执行 bara 超出范围但未释放。
    • @Farhad:我想我想说的是,“不,你不能。”
    • @MooingDuck 在这种情况下尝试在bar 中打印a 的值,看看是否出现编译错误。
    【解决方案5】:

    这个问题毫无意义。通常,线程的堆栈在创建线程时在进程堆上分配(内存保留和部分提交)。并在线程(通常)退出时释放。它在运行时具有固定的最大大小(保留内存),并通过从保留池中提交更多内存来“增长”。当函数调用使用堆栈时,不会发生实际的内存分配——函数使用的堆栈空间(对于它的局部变量)是一个预先分配和提交的内存区域。你不能取消分配它。

    想象一下,您在地址 addr 的堆上分配了 100 个字节,将指针传递给 addr+0x40 和大小 0x10 以使其在内部使用。函数可以在此地址创建一些变量(对象),总大小不超过 16 个字节,例如使用位置 new。它可以(并且通常应该)通过显式调用析构函数来销毁对象。但是它没有业务释放任何内存 - 传递给它的指针甚至不指向分配区域的开始......这很简单,堆栈是如何工作的 - 函数为其局部变量获取预分配内存的一部分,它在此内存中调用构造函数,然后在退出时调用析构函数。但它不会分配或释放任何堆栈空间。尝试这样做会导致访问冲突(分段错误)。

    【讨论】:

      【解决方案6】:

      不,在可移植 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
      }
      

      但是不要,有太多的问题要说。

      【讨论】:

        猜你喜欢
        • 2013-11-13
        • 2017-12-02
        • 2018-06-01
        • 1970-01-01
        • 2011-12-11
        • 1970-01-01
        • 2013-11-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多