考虑这个代码,有一个明显的编译错误:(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
是否有帮助 - nope :( 4)
struct A;
struct B {
B() { new A(); } // error: allocation of incomplete type 'A'
};
struct A {};
我认为它与template
有关,事实上:将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
的大小/定义来分配它,因此仅仅声明它是不够的。另外我相信,定义必须优先于分配。
这似乎是正确的,直接使用new
(1,4)。但是当new
被包裹时,显然我错了(2,3,5,6)。
我到目前为止找到的可能解释是:
template
实例化为止。我认为这是正确的,但在我的情况下,直接使用new A()
并且对my_new<A>()
的调用几乎发生在同一位置。所以这不是原因。正确?template
参数可能是未定义的行为。这是真的吗?即使启用所有警告,编译器也不会抱怨。同样比较5和6似乎表明,编译器足够聪明,可以理解,定义如下(因此实际上使类型完整)。为什么4被认为是不正确的,而5个编译(或者5只是虚假地编译未定义的行为[但是3必须也有缺陷,对吧?])?
btw:用clang ++ - 3.5.0和g ++ - 4.9.2
进行测试答案 0 :(得分:6)
§14.6.4.1[temp.point] / p1,8,强调我的:
1对于函数模板特化,成员函数模板 专业化,或成员函数或静态的专业化 如果专门化是隐式的,则为类模板的数据成员 实例化,因为它是从另一个模板中引用的 专业化和引用它的上下文取决于 模板参数,专业化的实例化点 是封闭专业化的实例化点。 否则,这种专业化的实例化点 紧跟在命名空间范围声明或定义之后 是指专业化。
8功能模板的专业化,成员函数模板, 或者类模板的成员函数或静态数据成员可以 在翻译单元中有多个实例化点,和 除了上面描述的实例化点之外,对于任何 这种专业化有一个实例化点 翻译单位,翻译单位的结尾也被认为是 实例化点。类模板的专业化有 翻译单元中的大多数实例化点。一个 任何模板的特化都可能有实例化点 多个翻译单位。 如果有两个不同的实例化点 根据一个给出模板专业化的不同含义 定义规则(3.2),该程序是不正确的,没有诊断 必需的。强>
my_new<A>
有两个实例化点,一个位于B
定义的末尾,一个位于翻译单元的末尾。由于这两点会产生不同的含义(对于片段3和5),程序是不正确的NDR(即,它具有未定义的行为)。