C ++, предотвращающий создание экземпляра класса в стеке (во время компиляции) - PullRequest
8 голосов
/ 22 июня 2010

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

MyClass c1; //compilation error

MyClass* c1 = new MyClass(); //compiles okay

При поиске в Интернете я обнаружил следующее предложение:

class MyClass {
public:
    MyClass();
private:
    void destroy() const { delete this; }

...

private:
    ~MyClass();
};

int main(int argc,char** argv)
{
    MyClass myclass; // <--- error, private destructor called here !!!

    MyClass* myclass_ptr = new MyClass;
    myclass_ptr->destroy();
}

Что яне понимаю, почему это должно работать.Зачем вызывать деструктор при создании экземпляра MyClass?

Ответы [ 5 ]

23 голосов
/ 22 июня 2010

Когда myclass достигает конца своей области (следующий }), компилятор вызывает деструктор, чтобы освободить его из стека.Однако, если деструктор закрыт, доступ к деструктору невозможен, поэтому класс нельзя поместить в стек.

Мне не нравится внешний вид delete this.В общем, я думаю, что объекты не должны разрушать себя.Возможно, лучший способ - использовать приватный конструктор для вашего класса, а затем использовать статическую функцию для создания экземпляра.

// In class declaration...
static MyClass* Create()
{
    return new MyClass(); // can access private constructor
}

// ...

MyClass myclass; // illegal, cannot access private constructor

MyClass* pMyClass = MyClass::Create();
delete pMyClass; // after usage
12 голосов
/ 22 июня 2010

Почему деструктор вызывается при создании экземпляра MyClass?

Это не так. Тем не менее, он должен вызываться автоматически, когда экземпляр выходит из области видимости. Если это приватно, компилятор не должен генерировать этот код, следовательно, ошибка.

Если вы думаете, что сделать приватный деструктор неясным, другой способ ограничить класс динамическим размещением - сделать все конструкторы приватными и иметь только функции MyClass::create(), возвращающие динамически распределенные объекты:

class MyClass {
public:
  static MyClass* create()             {return new MyClass();}
  static MyClass* create(const Foo& f) {return new MyClass(f);}
private:
  MyClass();
  MyClass(const Foo&);
};

Обратите внимание, что возвращение обнаженных указателей на объекты, которые должны быть удалены, осуждается Вместо этого вы должны вернуть умные указатели:

class MyClass {
public:
  static std::shared_ptr<MyClass> create()             {return new MyClass();}
  static std::shared_ptr<MyClass> create(const Foo& f) {return new MyClass(f);}
  // ...
};
1 голос
/ 22 июня 2010

Это не так. Компилятор пытается вызвать деструктор, когда он выходит из области видимости, и указывает на строку кода, которая производит этот эффект, что гораздо полезнее, чем указание на конец функции.

1 голос
/ 22 июня 2010

Всякий раз, когда локальная переменная выходит из области видимости, она уничтожается. А на уничтожение деструктор объекта называется. Здесь сфера является основной функцией. При выходе из программы деструктор объекта myclass будет называться

1 голос
/ 22 июня 2010

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

...