C++:未使用嵌入式模板调用析构函数

use*_*239 4 c++ templates destructor

简短:删除模板化指针不会调用析构函数.

包括解决问题.为什么?

我刚遇到一种我无法解释的情况.我试着在这里打破更复杂的局面.

文件R.cpp

class R {
      Owner<Problem> m_o;
      void cleanUp() { m_o.clear(); }
     }
Run Code Online (Sandbox Code Playgroud)

文件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();
}
Run Code Online (Sandbox Code Playgroud)

我现在有一个实用程序类,它在堆上创建新的Problem-objects并直接将它们插入到m_o中.我知道导出对内部类型的引用是不好的方式,但这不是重点.

如果我调用cleanUp(),我可以将其追溯到Functor中的调用delete ptr,其中ptr具有正确的Problem-type.但问题 - 析构函数没有被调用!!

但是,在文件R.cpp中包含问题标题可以解决问题.这位编辑不抱怨.这是编译器错误吗?

系统:g ++(Ubuntu 4.8.2-19ubuntu1)4.8.2

eer*_*ika 5

从标准(草案n3242)§5.3.5/ 5:

如果被删除的对象在删除时具有不完整的类类型,并且完整的类具有非平凡的析构函数或释放函数,则行为是未定义的.

如果您没有包含定义的标题TProblem在这种情况下,那么您将删除不完整类型的对象.如果该类型不满足该子句中的要求,则删除具有未定义的行为.

这是编译器错误吗?

不,编译器不需要警告未定义的行为.

您可能要需要TOwner是完整的.喜欢的东西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;
Run Code Online (Sandbox Code Playgroud)

请注意,您实际上是部分重新实现了std::vector<std::unique_ptr<T>>如果您可以使用c ++ 11,我建议您使用它.