C++, предотвращающий создание экземпляра класса в стеке (во время компиляции)
Я знаю, что есть методы, чтобы предотвратить создание класса в куче, предотвращая использование пользователем 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 ответов
Когда 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
Зачем вызывать деструктор при создании экземпляра
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);}
// ...
};
Это не так. Компилятор пытается вызвать деструктор, когда он выходит из области видимости, и указывает на строку кода, которая производит этот эффект, что гораздо полезнее, чем указание на конец функции.
Всякий раз, когда локальная переменная выходит из области видимости, она уничтожается. А на уничтожение, деструктор объекта называется. Здесь сфера является основной функцией. При выходе из программы вызывается деструктор объекта myclass
Потому что когда экземпляр выходит из области видимости, он должен быть уничтожен с помощью деструктора. Указатель на экземпляр не делает этого.