new 在堆栈而不是堆上(如 alloca 与 malloc)

Posted

技术标签:

【中文标题】new 在堆栈而不是堆上(如 alloca 与 malloc)【英文标题】:new on stack instead of heap (like alloca vs malloc) 【发布时间】:2010-10-03 02:08:04 【问题描述】:

有没有办法使用new 关键字在堆栈(ala alloca)而不是堆(malloc)上分配?

我知道我可以自己破解,但我不想这样做。

【问题讨论】:

【参考方案1】:

你可以这样做:

Whatever* aWhatever = new ( alloca(sizeof(Whatever)) ) Whatever;

您可以使用 RAII 类来进行我认为的破坏(编辑:另见 this other answer for more information on potential problems with this approach):

template <class TYPE>
class RAII
    
    public:
        explicit RAII( TYPE* p ) : ptr(p) 
        ~RAII()  ptr->~TYPE(); 
        TYPE& operator*() const  return *ptr; 
    private:
        TYPE* ptr;
    

void example()
    
    RAII<Whatever> ptr = new ( alloca(sizeof(Whatever)) ) Whatever;
    

您可以使用宏来隐藏 alloca。

问候 戴夫F

【讨论】:

【参考方案2】:

在 GCC 中使用 _alloca() 时要小心

GCC 在 C++ 中有一个bug which makes _alloca() incompatible with SJLJ exception handling(据报道 Dwarf2 可以正常工作)。当分配内存的函数抛出异常时,该错误会在析构函数开始运行之前导致堆栈损坏。这意味着在分配的对象上工作的任何 RAII 类都必须在另一个函数中运行才能正常工作。正确的做法是这样的:

void AllocateAndDoSomething()

  Foo* pFoo = reinterpret_cast<Foo*>(_alloca(sizeof(Foo)));
  new (pFoo) Foo;

  // WARNING: This will not work correctly!
  // ScopedDestructor autoDestroy(pFoo);
  // pFoo->DoSomething();

  // Instead, do like this:
  DoSomething(pFoo);


void DoSomething(Foo* pFoo)

  // Here, destruction will take place in a different call frame, where problems
  // with _alloca() automatic management do not occur.
  ScopedDestructor autoDestroy(pFoo);
  pFoo->DoSomething();

【讨论】:

【参考方案3】:

Jeffrey Hantin 非常正确,您可以使用placement new 在alloca 的堆栈上创建它。但是,说真的,为什么?相反,只需这样做:

class C  /* ... */ ;

void func() 
    C var;
    C *ptr = &var;

    // do whatever with ptr

您现在有一个指向堆栈上分配的对象的指针。而且,当你的函数存在时,它会被正确地销毁。

【讨论】:

您的示例正是我将其声明为按值的局部变量的意思。 注意:如果你已经定义了一个非空的构造函数,该类必须在 cpp 中定义一个空的构造函数。 我的用例 - 比如说 C 在子类 C1C2 中覆盖了 virtual 方法。那我可能想做C * ptr = criteria ? new (alloca(sizeof(C1))) C1(...) : new (alloca(sizeof(C2))) C2(...);【参考方案4】:

要在堆栈上分配,要么将你的对象声明为局部变量按值,或者你可以实际使用 alloca 来获取指针,然后使用就地 new 运算符:

void *p = alloca(sizeof(Whatever));
new (p) Whatever(constructorArguments);

但是,虽然使用 alloca 和 in-place new 可确保在返回时释放内存,但您放弃了自动析构函数调用。如果您只是想确保在退出作用域时释放内存,请考虑使用std::auto_ptr&lt;T&gt; 或其他一些智能指针类型。

【讨论】:

以上是关于new 在堆栈而不是堆上(如 alloca 与 malloc)的主要内容,如果未能解决你的问题,请参考以下文章

将 alloca() 用于可变长度数组是不是比在堆上使用向量更好?

为啥 alloca 与创建局部变量不同?

如何重载 new 运算符以在堆栈上分配? [关闭]

为啥要在堆上而不是栈上分配内存? [复制]

如何确定 Rust 中的 new() 何时在堆栈或堆上分配

java中的堆栈