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

C++: Destructor not called with embedded template

本文关键字:调用 析构函数 未使用 C++      更新时间:2023-10-16

简而言之:删除模板化指针不会调用析构函数。

include解决了问题。为什么

我只是遇到了一个我无法解释的情况。我试图打破这里更复杂的局面。

文件R.cpp

class R {
      Owner<Problem> m_o;
      void cleanUp() { m_o.clear(); }
     }

文件所有者.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对象,并将它们直接插入m_o中。我知道将引用导出到内部类型是不好的风格,但这不是重点。

如果我调用cleanUp(),我可以追踪到Functor中的调用delete ptr,其中ptr具有正确的Problem类型。但是问题析构函数没有被调用!!

但是,在R.cpp文件中包含Problem标头可以修复该问题。滑稽演员没有抱怨。这是编译器错误吗?

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

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

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

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

这是编译器错误吗?

不需要,编译器不需要对未定义的行为发出警告。

您可能需要Owner中的T是完整的。如果T不完整,像static_assert(sizeof(T) > 0)这样的东西应该无法编译。

如果不能依赖当前的标准,则可以使用boost::checked_deleter作为删除函数。它在预c++11中进行完整性检查。如果你出于某种原因不想包含boost头,那么就重新实现它。这是检查完整性的代码。

// 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,我建议您改用它。