Как я могу предотвратить распределение класса с помощью оператора 'new'? (Я хотел бы убедиться, что мой класс RAII всегда размещается в стеке.) - PullRequest
42 голосов
/ 24 сентября 2008

Я хочу убедиться, что мой класс RAII всегда размещен в стеке.

Как предотвратить присвоение класса с помощью оператора 'new'?

Ответы [ 4 ]

51 голосов
/ 24 сентября 2008

Все, что вам нужно сделать, это объявить новый оператор класса 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
    // ...
};  

Создание приватного «оператора new» эффективно не позволяет коду вне класса использовать «new» для создания экземпляра X.

Для завершения вы должны скрыть «оператор удаления» и версии обоих операторов в массиве.

Начиная с C ++ 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;
};

Смежный вопрос: Можно ли предотвратить размещение объекта в стеке и разрешить его инициацию только с помощью 'new'?

6 голосов
/ 24 сентября 2008

Я не уверен в вашей мотивации.

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

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

т.е. как то так:

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

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

2 голосов
/ 24 сентября 2008

@ 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(); 
0 голосов
/ 24 сентября 2008

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

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

...