use*_*239 4 c++ templates destructor
简短:删除模板化指针不会调用析构函数.
我刚遇到一种我无法解释的情况.我试着在这里打破更复杂的局面.
文件R.cpp
class R {
      Owner<Problem> m_o;
      void cleanUp() { m_o.clear(); }
     }
文件Owner.cpp
struct DeleteFunctor {
  template< class TPtr > void operator()(TPtr* ptr) {  delete ptr; }
};
template< class T >
class Owner { 
std::vector<T*> m_objects; 
// here add and other stuff
void clear() {
  std::for_each( m_objects.begin(), m_objects.end(), DeleteFunctor() );
  m_objects.clear();
}
我现在有一个实用程序类,它在堆上创建新的Problem-objects并直接将它们插入到m_o中.我知道导出对内部类型的引用是不好的方式,但这不是重点.
如果我调用cleanUp(),我可以将其追溯到Functor中的调用delete ptr,其中ptr具有正确的Problem-type.但问题 - 析构函数没有被调用!!
但是,在文件R.cpp中包含问题标题可以解决问题.这位编辑不抱怨.这是编译器错误吗?
系统:g ++(Ubuntu 4.8.2-19ubuntu1)4.8.2
从标准(草案n3242)§5.3.5/ 5:
如果被删除的对象在删除时具有不完整的类类型,并且完整的类具有非平凡的析构函数或释放函数,则行为是未定义的.
如果您没有包含定义的标题T或Problem在这种情况下,那么您将删除不完整类型的对象.如果该类型不满足该子句中的要求,则删除具有未定义的行为.
这是编译器错误吗?
不,编译器不需要警告未定义的行为.
您可能要需要T的Owner是完整的.喜欢的东西static_assert(sizeof(T) > 0)应该编译失败,如果T是不完整的.
如果您不能依赖当前标准,则可以将其boost::checked_deleter用作删除仿函数.它在pre c ++ 11中进行完整性检查.如果由于某种原因不希望包含升压头,那么只需重新实现它.这是检查完整性的代码.
// intentionally complex - simplification causes regressions
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x;
请注意,您实际上是部分重新实现了std::vector<std::unique_ptr<T>>如果您可以使用c ++ 11,我建议您使用它.