В конструкторе X
, если new
терпит неудачу, он генерирует исключение (std::bad_alloc
). Это означает, что конструктор никогда не завершается, поэтому время жизни объекта никогда не начинается, поэтому его деструктор никогда не вызывается (объекта нет), и между new[]
и delete[]
нет несоответствия. (X
должен иметь объявленный пользователем конструктор копирования и объявленный пользователем оператор копирования, поскольку предоставленная реализация нарушит эту гарантию, если построение завершится успешно, и объект будет скопирован или назначен.)
В Y
, если он выделяет память в своем конструкторе, и это распределение успешно, тогда он должен гарантировать, что эта память освобождается, если остальная часть конструкции выдает исключение в любой точке и, если конструктор завершает, что в деструкторе освобождается память (при условии, что память рассчитана на длительность жизни объекта).
Чтобы сделать это проще, любая выделенная память должна быть немедленно передана объекту, единственной обязанностью которого является освобождение памяти. Наличие одного класса для управления необработанными указателями на несколько блоков выделенной памяти - это рецепт сложного и подверженного ошибкам кода управления.