如何在编译时检测普通的析构函数?

时间:2012-03-25 07:46:13

标签: c++ sfinae

我有一个模板化的容器类,看起来像这样:

template <class ItemType> class MyContainer
{
public:
   [... various methods omitted for brevity...]

   void Clear()
   {
      ItemType defaultItem;
      for (int i=0; i<_numValidItems; i++) _itemArray[i] = defaultItem;
      _numValidItems = 0;
   }

   void FastClear()
   {
      _numValidItems = 0;
   }

private:
   int _numValidItems;
   ItemType * _itemArray;
};

正如您所看到的,Clear()方法将容器中的每个项重置为其默认状态,这对于以下类型的类型是必要的。单个项目已动态分配我希望Clear()调用释放的内部资源。

还有FastClear(),顾名思义它更快(O(1)而不是O(N)),因为它只是将_numValidItems设置为零,并且实际上并没有接触到任何项目。阵列。这对于POD风格的ItemTypes来说非常好,但对于例如文件句柄类型。

我的问题是,有没有办法使用SFINAE或类似方法让编译器在编译时决定使Clear()成为FastClear()的同义词是安全的,即当ItemType有一个简单的析构函数时?这样调用代码就不必记住调用FastClear()而不是Clear来获得加速,它会自动工作。

另外,只是为了让事情变得更加困难......我希望能够在不增加对Boost / TR1 / C ++ 11的依赖性的情况下做到这一点。 (所以调用is_pod()或has_trivial_destructor()对我来说不是好选择)

2 个答案:

答案 0 :(得分:5)

调用析构函数的正确方法是

void Clear()
{
    for (int i = 0; i < _numValidItems; ++ i)
    {
        _itemArray[i].~ItemType();
    }
    _numValidItems = 0;
}

gcc 4.6上的优化器(在-O2或以上)将在析构函数很简单时消除循环(不确定4.2,你自己检查)。例如,如果ItemType等于std::pair<double, double>,则您的Clear()版本会生成

0000000000000000 <_ZN11MyContainerISt4pairIddEE8BadClearEv>:
   0:   8b 0f                   mov    ecx,DWORD PTR [rdi]
   2:   85 c9                   test   ecx,ecx
   4:   7e 34                   jle    3a <_ZN11MyContainerISt4pairIddEE8BadClearEv+0x3a>
   6:   83 e9 01                sub    ecx,0x1
   9:   48 8b 57 08             mov    rdx,QWORD PTR [rdi+0x8]
   d:   31 c0                   xor    eax,eax
   f:   48 83 c1 01             add    rcx,0x1
  13:   48 c1 e1 04             shl    rcx,0x4
  17:   66 0f 1f 84 00 00 00    nop    WORD PTR [rax+rax*1+0x0]
  1e:   00 00 
  20:   48 c7 04 02 00 00 00    mov    QWORD PTR [rdx+rax*1],0x0
  27:   00 
  28:   48 c7 44 02 08 00 00    mov    QWORD PTR [rdx+rax*1+0x8],0x0
  2f:   00 00 
  31:   48 83 c0 10             add    rax,0x10
  35:   48 39 c8                cmp    rax,rcx
  38:   75 e6                   jne    20 <_ZN11MyContainerISt4pairIddEE8BadClearEv+0x20>
  3a:   c7 07 00 00 00 00       mov    DWORD PTR [rdi],0x0
  40:   c3                      ret    

我的版本生成

0000000000000000 <_ZN11MyContainerISt4pairIddEE5ClearEv>:
   0:   c7 07 00 00 00 00       mov    DWORD PTR [rdi],0x0
   6:   c3                      ret    

由于gcc 4.2已与TR1捆绑在一起,我不知道为什么你不能使用std::tr1::has_trivial_destructor

答案 1 :(得分:0)

我和Boost Type Traits一起去enable_if。我认为它非常接近你的问题。如果你不想要包含,你可以自己实现它,使用Boost获取灵感。毕竟它使用SFINAE。