Почему нельзя вызывать конструкторы, а деструкторы?

В следующем коде C ++ мне разрешено явно вызывать деструктор, но не конструктор. Это почему? Не будет явным вызовом ctor больше выразительный а также унифицированный с делом дтор?

class X { };

int main() {
X* x = (X*)::operator new(sizeof(X));
new (x) X;  // option #1: OK
x->X();     // option #2: ERROR

x->~X();
::operator delete(x);
}

28

Решение

Потому что до запуска конструктора нет объекта типа X по этому адресу. Как таковая, разыменование x как X тип или доступ к членам / методам его будет неопределенным поведением.

Так что основная разница между x->X(); (гипотетический синтаксис) и x->~X() является то, что во втором случае у вас есть объект, для которого вы можете вызвать (специальный) член, такой как деструктор, в то время как в первом случае, пока нет объекта по которому можно вызывать методы (даже специальный метод — конструктор).

Вы можете утверждать, что может существовать исключение из этого правила, но в конечном итоге это будет зависеть от синтаксических предпочтений, когда в обоих случаях возникают несоответствия. С текущим синтаксисом вызов конструктора не похож на вызов конструктора, в предложенном вами синтаксисе будет симметрия с вызовом деструктора, но несоответствия в правилах, которые определяют, когда вы можете разыменовывать / получать доступ к методам объекта. На самом деле должно быть исключение, позволяющее вызывать метод для чего-то, что еще не является объектом. Тогда вам придется строго определить букву стандарта то, что еще не является объектом.

37

Другие решения

Это вариант проблемы курицы и яйца.

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

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

Единственное исключение из этого — когда вы выделили память для объекта, но еще не инициализировали экземпляр (т.е. память для экземпляра есть, но она не была инициализирована, чтобы стать действительным экземпляром). Следовательно, вам нужно вызвать конструктор. Это ситуация, когда размещение new, синтаксис, который вы показываете под комментарием «вариант 1», полезен. Тем не менее, это не вызов участника, который вы выполняете для экземпляра, поскольку экземпляр недоступен до выполнения этого вызова.

9

Вы можете построить объект в произвольном месте, используя новое размещение.

Вызов new () может быть перекрыт параметрами; конструктор размещения принимает либо void*или указатель на тип. Функция new () всегда принимает параметр size_t, который имеет тип sizeof (); это обычно используется только глобальной новой функцией

Конструктор размещения и деструктор экспликации используются при записи пулов памяти.

Например (из памяти!)

class MyClass
{
public:
inline new(size_t size, MyClass *ptr) { return ptr; };
};

Используется так

{
MyClass *x = ...;
MyClass *y = new (x) MyClass(construct parameters);
x->~MyClass();
}

Отредактировано, чтобы исправить ошибку, указанную @ Ben-Voigt

-1
По вопросам рекламы [email protected]