новое в стеке вместо кучи (например, alloca против malloc) - PullRequest
15 голосов
/ 23 января 2009

Есть ли способ использовать ключевое слово new для размещения в стеке (ala alloca) вместо кучи (malloc)?

Я знаю, что могу взломать свой собственный, но я бы не стал.

Ответы [ 4 ]

23 голосов
/ 23 января 2009

Чтобы выделить в стеке, либо объявите свой объект как локальную переменную по значению , либо вы можете использовать alloca для получения указателя, а затем использовать оператор new на месте:

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

Однако, используя alloca и in-place, new гарантирует, что память освобождается при возврате, вы прекращаете автоматический вызов деструктора. Если вы просто пытаетесь убедиться, что память освобождается при выходе из области, рассмотрите возможность использования std::auto_ptr<T> или другого типа интеллектуального указателя.

12 голосов
/ 23 января 2009

Джеффри Хантин совершенно прав, что вы можете использовать новое размещение, чтобы создать его в стеке с помощью alloca. Но серьезно, почему ?! Вместо этого просто сделайте:

class C { /* ... */ };

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

    // do whatever with ptr
}

Теперь у вас есть указатель на объект, размещенный в стеке. И он будет должным образом уничтожен, когда ваша функция существует.

5 голосов
/ 23 января 2009

Вы можете сделать:

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

Вы могли бы использовать класс RAII для уничтожения, я полагаю (РЕДАКТИРОВАТЬ: См. Также этот другой ответ для получения дополнительной информации о потенциальных проблемах с этим подходом ):

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;
    }

Вы можете использовать макрос, чтобы скрыть выделение.

С уважением DaveF

2 голосов
/ 24 октября 2009

Будьте осторожны при использовании _alloca() с GCC

GCC содержит ошибку , из-за которой _alloca() несовместим с обработкой исключений SJLJ в C ++ (сообщается, что 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();
}
...