Как предотвратить распределение класса с помощью "нового" оператора? (Я бы хотел, чтобы мой класс RAII всегда был выделен в стеке.)

Я бы хотел, чтобы мой класс RAII всегда был выделен в стеке.

Как предотвратить выделение класса с помощью "нового" оператора?

Ответ 1

Все, что вам нужно сделать, это объявить класс новым оператором private:

class X
{
    private: 
      // Prevent heap allocation
      void * operator new   (size_t);
      void * operator new[] (size_t);
      void   operator delete   (void *);
      void   operator delete[] (void*);

    // ...
    // The rest of the implementation for X
    // ...
};  

Создание "operator new" private эффективно предотвращает использование кода за пределами класса "new" для создания экземпляра X.

Чтобы выполнить все, вы должны скрыть "оператор delete" и версии массива обоих операторов.

С С++ 11 вы также можете явно удалить функции:

class X
{
// public, protected, private ... does not matter
    static void *operator new     (size_t) = delete;
    static void *operator new[]   (size_t) = delete;
    static void  operator delete  (void*)  = delete;
    static void  operator delete[](void*)  = delete;
};

Связанный с этим вопрос: Возможно ли предотвратить размещение стека в стеке и разрешить его только с помощью нового? p >

Ответ 2

Я не убежден в вашей мотивации.

Есть веские причины для создания классов RAII в свободном хранилище.

Например, у меня есть класс блокировки RAII. У меня есть путь через код, где блокировка необходима только в случае определенных условий (это видеопроигрыватель, и мне нужно только удерживать блокировку во время моего цикла рендеринга, если у меня загружено и воспроизводится видео, если ничего не загружено, Мне это не нужно). Таким образом, возможность создания блокировок в свободном хранилище (с scoped_ptr/auto_ptr) очень полезна; он позволяет мне использовать один и тот же код, независимо от того, нужно ли вытащить блокировку.

то есть. что-то вроде этого:

auto_ptr<lock> l;
if(needs_lock)
{
    l.reset(new lock(mtx));
}
render();

Если бы я мог создавать блокировки в стеке, я бы не смог этого сделать.

Ответ 3

@DrPizza:

Это интересный момент, который у вас есть. Обратите внимание, что есть ситуации, когда идиома RAII необязательно является необязательной.

В любом случае, возможно, лучший способ подойти к вашей дилемме - добавить параметр к конструктору блокировки, который указывает, нужна ли блокировка. Например:

class optional_lock
{
    mutex& m;
    bool dolock;

public:
    optional_lock(mutex& m_, bool dolock_)
        : m(m_)
        , dolock(dolock_)
    {
        if (dolock) m.lock();
    }
    ~optional_lock()
    {
        if (dolock) m.unlock();
    }
};

Тогда вы могли бы написать:

optional_lock l(mtx, needs_lock);
render(); 

Ответ 4

В моей конкретной ситуации, если блокировка не нужна, мьютекс вообще не существует, поэтому я думаю, что подход будет гораздо сложнее.

Я думаю, что я действительно пытаюсь понять, это оправдание запрета на создание этих объектов в свободном хранилище.