Когда тип считается завершенным?
Рассмотрим следующий фрагмент кода. Деструктор 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.
1 ответ
5.3.5 Удалить
[expr.delete]
5 Если удаляемый объект имеет неполный тип класса в точке удаления, а полный класс имеет нетривиальный деструктор или функцию освобождения, поведение не определено.
Таким образом, вы, конечно, ожидаете, что это будет UB, так как Widget::~Widget()
является нетривиальным, и вы ожидаете, что безопасный буст в форсированном режиме выдает ошибку.
Теперь давайте копать выше:
2.2 Фазы перевода
[lex.phases]
8 Переведенные единицы перевода и единицы создания экземпляров объединяются следующим образом: [Примечание: ... ] Каждая переведенная единица перевода проверяется для составления списка необходимых экземпляров. [Примечание: это может включать в себя экземпляры, которые были явно запрошены (14.7.2). - примечание] Определения необходимых шаблонов находятся. Это зависит от реализации, должен ли быть доступен источник блоков перевода, содержащих эти определения. [Примечание: реализация может закодировать достаточную информацию в переведенную единицу перевода, чтобы гарантировать, что источник здесь не требуется. —Конец примечания] Все необходимые экземпляры выполняются для создания единиц реализации. [Примечание: они похожи на переведенные единицы перевода, но не содержат ссылок на необоснованные шаблоны и определения шаблонов. - примечание] Программа плохо сформирована, если какая-либо инстанция не удалась.
Вы сохранены фазами перевода:
Переведите модуль перевода, затем создайте шаблоны...