新的不完整类型在包装在模板中时编译
new of incomplete type compiles when wrapped in template
考虑这段代码,有一个明显的编译错误:(1)
struct A;
struct B {
B() { new A(); } // error: allocation of incomplete type 'A'
};
使用 unique_ptr
也无济于事:(2)
struct A;
struct B {
B() { std::make_unique<A>(); } // error: due to ~unique_ptr()
};
然后(令我大吃一惊)我发现,这个 将 编译:(3)
struct A;
struct B {
B() { std::make_unique<A>(); }
};
struct A {}; // OK, when a definition is added **below**
然后我检查了,这对 new
是否也有帮助 - 没有: (4)
struct A;
struct B {
B() { new A(); } // error: allocation of incomplete type 'A'
};
struct A {};
我认为它与 template
s 有关,事实上:将 new
包装在 template
中 编译:( 5)
template <typename T>
T* my_new() { return new T(); } // OK, when wrapped in template
struct A;
struct B {
B() { my_new<A>(); }
};
struct A {};
为了完整起见,删除 A
的定义会再次引发错误:(6)
template <typename T>
T* my_new() { return new T(); } // error: allocation of incomplete type 'A'
struct A;
struct B {
B() { my_new<A>(); }
};
// do note: definition of A removed
这是怎么回事?据我理解,编译器必须知道A
的size/definition来分配它,因此仅仅声明它, 是不够的。另外我相信,定义必须先于分配。
这似乎是正确的,当直接使用 new
(1,4) 时。但是当new
换行的时候,很明显是我弄错了(2,3,5,6).
目前我发现的可能的解释是:
- 完成类型的检查被延迟到
template
实例化发生。我认为这是正确的,但在我的例子中,new A()
的 直接 使用和对 my_new<A>()
的调用几乎发生在同一位置。所以这不能成为原因。对吗?
- 使用不完整的类型作为
template
参数可能是 未定义的行为。这是真的吗?即使启用所有警告,编译器也不会抱怨。比较 5 和 6 似乎表明,编译器足够聪明,可以找出下面的定义(因此实际上使类型完整)。
为什么 4 被认为是不正确的,而 5 是编译的(或者 5 只是虚假地编译了未定义的行为 [但是 3 一定也有缺陷,对吧?])?
顺便说一句:使用 clang++-3.5.0 和 g++-4.9.2 测试
§14.6.4.1 [temp.point]/p1,8,强调我的:
1 For a function template specialization, a member function template
specialization, or a specialization for a member function or static
data member of a class template, if the specialization is implicitly
instantiated because it is referenced from within another template
specialization and the context from which it is referenced depends on
a template parameter, the point of instantiation of the specialization
is the point of instantiation of the enclosing specialization.
Otherwise, the point of instantiation for such a specialization
immediately follows the namespace scope declaration or definition that
refers to the specialization.
8 A specialization for a function template, a member function template,
or of a member function or static data member of a class template may
have multiple points of instantiations within a translation unit, and
in addition to the points of instantiation described above, for any
such specialization that has a point of instantiation within the
translation unit, the end of the translation unit is also considered a
point of instantiation. A specialization for a class template has at
most one point of instantiation within a translation unit. A
specialization for any template may have points of instantiation in
multiple translation units. If two different points of instantiation
give a template specialization different meanings according to the one
definition rule (3.2), the program is ill-formed, no diagnostic
required.
my_new<A>
有两个实例化点,一个在B
定义的末尾,一个在翻译单元的末尾。由于这两点将导致不同的含义(对于代码段 3 和 5),该程序是格式错误的 NDR(即,它具有未定义的行为)。
考虑这段代码,有一个明显的编译错误:(1)
struct A;
struct B {
B() { new A(); } // error: allocation of incomplete type 'A'
};
使用 unique_ptr
也无济于事:(2)
struct A;
struct B {
B() { std::make_unique<A>(); } // error: due to ~unique_ptr()
};
然后(令我大吃一惊)我发现,这个 将 编译:(3)
struct A;
struct B {
B() { std::make_unique<A>(); }
};
struct A {}; // OK, when a definition is added **below**
然后我检查了,这对 new
是否也有帮助 - 没有: (4)
struct A;
struct B {
B() { new A(); } // error: allocation of incomplete type 'A'
};
struct A {};
我认为它与 template
s 有关,事实上:将 new
包装在 template
中 编译:( 5)
template <typename T>
T* my_new() { return new T(); } // OK, when wrapped in template
struct A;
struct B {
B() { my_new<A>(); }
};
struct A {};
为了完整起见,删除 A
的定义会再次引发错误:(6)
template <typename T>
T* my_new() { return new T(); } // error: allocation of incomplete type 'A'
struct A;
struct B {
B() { my_new<A>(); }
};
// do note: definition of A removed
这是怎么回事?据我理解,编译器必须知道A
的size/definition来分配它,因此仅仅声明它, 是不够的。另外我相信,定义必须先于分配。
这似乎是正确的,当直接使用 new
(1,4) 时。但是当new
换行的时候,很明显是我弄错了(2,3,5,6).
目前我发现的可能的解释是:
- 完成类型的检查被延迟到
template
实例化发生。我认为这是正确的,但在我的例子中,new A()
的 直接 使用和对my_new<A>()
的调用几乎发生在同一位置。所以这不能成为原因。对吗? - 使用不完整的类型作为
template
参数可能是 未定义的行为。这是真的吗?即使启用所有警告,编译器也不会抱怨。比较 5 和 6 似乎表明,编译器足够聪明,可以找出下面的定义(因此实际上使类型完整)。
为什么 4 被认为是不正确的,而 5 是编译的(或者 5 只是虚假地编译了未定义的行为 [但是 3 一定也有缺陷,对吧?])?
顺便说一句:使用 clang++-3.5.0 和 g++-4.9.2 测试
§14.6.4.1 [temp.point]/p1,8,强调我的:
1 For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization and the context from which it is referenced depends on a template parameter, the point of instantiation of the specialization is the point of instantiation of the enclosing specialization. Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.
8 A specialization for a function template, a member function template, or of a member function or static data member of a class template may have multiple points of instantiations within a translation unit, and in addition to the points of instantiation described above, for any such specialization that has a point of instantiation within the translation unit, the end of the translation unit is also considered a point of instantiation. A specialization for a class template has at most one point of instantiation within a translation unit. A specialization for any template may have points of instantiation in multiple translation units. If two different points of instantiation give a template specialization different meanings according to the one definition rule (3.2), the program is ill-formed, no diagnostic required.
my_new<A>
有两个实例化点,一个在B
定义的末尾,一个在翻译单元的末尾。由于这两点将导致不同的含义(对于代码段 3 和 5),该程序是格式错误的 NDR(即,它具有未定义的行为)。