我有一个模板化的容器类,看起来像这样:
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()对我来说不是好选择)
答案 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。