我写了这篇文章,并得到了一些让我感到困惑的评论。
它基本上归结为我T2
只看到用作模板参数并错误地得出结论,因此我可以利用前向声明的机会:
struct T2;
struct T1
{
std::auto_ptr<T2> obj;
};
如果我不继续在T2
同一个 TU 中的某个地方定义,这将调用 UB,因为std::auto_ptr<T2>
调用delete
它的 internal T2*
,并调用delete
指向一个不完整类型的对象的指针,该对象的完整类型具有非平凡的析构函数是 undefined:
[C++11: 5.3.5/5]:
如果要删除的对象在删除点具有不完整的类类型,并且完整的类具有非平凡的析构函数或释放函数,则行为未定义。
我碰巧使用的 GCC 工具链 — v4.3.3 (Sourcery G++ Lite 2009q1-203) — 很友好地让我知道了一个注释:
注意:析构函数和特定于类的操作符 delete 都不会被调用,即使它们是在定义类时声明的。
尽管在其他 GCC 版本中似乎很难得到这种诊断。
我的抱怨是,如果指向不完整类型的实例的指针格式错误而不是 UB,那么发现这样的错误会容易得多delete
,但这对于实现来说似乎是一个难以解决的问题,所以我明白为什么是UB。
但后来有人告诉我,如果我std::unique_ptr<T2>
改用它,这将是安全且合规的。
据称 n3035 在 20.9.10.2 说:
的模板参数可能是不完整的类型
T
。unique_ptr
我只能在 C++11 中找到:
[C++11: 20.7.1.1.1]:
/1类模板
default_delete
用作类模板的默认删除器(破坏策略)unique_ptr
。/2的模板参数可能是不完整的类型
T
。default_delete
但是,default_delete
'soperator()
确实需要一个完整的类型:
[C++11: 20.7.1.1.2/4]:
如果T
是不完整类型,则程序格式错误。
我想我的问题是这样的:
我文章的评论者是否正确地说仅包含以下代码的翻译单元格式正确且定义明确?还是他们错了?
struct T2;
struct T1
{
std::unique_ptr<T2> obj;
};
如果它们是正确的,那么编译器将如何实现这一点,因为它有充分的理由成为 UB,至少在使用 an 时std::auto_ptr
?