Когда тип считается завершенным?

Рассмотрим следующий фрагмент кода. Деструктор boost :: scoped_ptr вызывается в конце основной функции. Деструктор использует boost :: checked_delete для освобождения инкапсулированного указателя виджета.

#include <boost/scoped_ptr.hpp>
#include <iostream>

class Widget;
Widget *make_widget();

int main()
{
boost::scoped_ptr<Widget> sp(make_widget());
// std::cout << sizeof(Widget) << std::endl;
}

class Widget
{
public:
Widget() {}
~Widget() { std::cout << "Widget destructor called." << std::endl; }
};

Widget *make_widget()
{
return new Widget;
}

Я ожидал, что этот код не сможет скомпилироваться, так как класс Widget неполон в момент, когда деструктор scoped_ptr<Widget> вызывается. Однако это компилируется чисто на g ++ 4.8 и Visual Studio 2010. Обратите внимание на закомментированный оператор с sizeof(Widget) Выражение в основной функции. Если я раскомментирую его, он не будет компилироваться, подразумевая, что Widget должно быть неполным в этой точке.

Каково правильное объяснение этого поведения?

РЕДАКТИРОВАТЬ: Некоторые ответы (в настоящее время удалены) указали на неопределенное поведение, но я ожидал бы использование check_delete в scoped_ptrдеструктор, чтобы вызвать сбой компиляции. FWIW, я использую Boost 1.55.

8

Решение

5.3.5 Удалить [expr.delete]

5 Если удаляемый объект имеет неполный тип класса в точке удаления, а полный класс имеет нетривиальный деструктор или функцию освобождения, поведение не определено.

Таким образом, вы, конечно, ожидаете, что это будет UB, так как Widget::~Widget() является нетривиальным, и вы ожидаете, что безопасный буст в форсировке выдает ошибку.

Теперь давайте копать выше:

2.2 Фазы перевода [lex.phases]

8 Переводимые единицы перевода и экземпляры создаются следующим образом: [ Заметка: … ] Каждая переведенная единица перевода проверяется для составления списка необходимых экземпляров. [Примечание: это может включать в себя экземпляры, которые были явно запрошены (14.7.2). —Конечная записка] Определения необходимых шаблонов находятся. Это зависит от реализации, должен ли быть доступен источник блоков перевода, содержащих эти определения. [Примечание: реализация может закодировать достаточную информацию в переведенную единицу перевода, чтобы гарантировать, что источник здесь не требуется. —Конечная записка] Все необходимые экземпляры выполняются для создания единиц реализации. [Примечание: они похожи на переведенные единицы перевода, но не содержат ссылок на необоснованные шаблоны и определения шаблонов. —Конечная записка] Программа плохо сформирована, если какая-либо инстанциация не удалась.

Вы спасены этапы перевода:
Переведите переводческий блок, затем создавать шаблоны …

4

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