检测类型何时不需要调用其析构函数

问题描述 投票:4回答:3

我正在编写一个C ++ 11 STL兼容的分配器,我想知道如何检测安全的类型,不要调用它们的析构函数(在allocator<T>::destroy方法中)。

我已经编写了分配器(一个简单的分配器),据我所知,它确实有效。我问的原因是我的代码中有警告(即我的分配器的destroy方法。)我在最高警告级别使用VS2013(vc12),警告是:

warning C4100: 'c' : unreferenced formal parameter

在这个方法中:

template <typename T>
class MyAlloc
{
    ...

    template <typename C>
    void destroy (C * c) // <-- this is the 'c' that the warning is referring to
    {
        c->~C ();
    }

    ...
};

如您所见,警告和代码都非常简单明了。在我看来发出警告是因为这个分配器使用的一些类没有析构函数(例如因为它们是POD等)。随后,编译器在上面的函数中删除了对析构函数的调用。正在为这些类实例化分配器,然后,看到函数体为空且参数未使用,则发出警告。

我想我可以编写上面的destroy方法的两个版本,使用enable_if重载,并将主体留空,并且在不需要破坏的类的重载中未命名参数。这会有用吗?

另一方面,这个警告是一个非常小的不便。我可以禁用此特定警告,它对我的​​代码库没有太大影响。毕竟,这不是一个有用的警告。

但是,如果我确实尝试更改我的代码并检测不需要破坏的类,但是做得不可靠和糟糕,我会为各种各样的痛苦和痛苦打开闸门。因为如果我碰巧没有破坏一个确实需要破坏的类的实例,只有众神知道什么可以(并且会)出错!因此,如果没有100%可靠且稳健的方法来检测这些类并处理它们,我更愿意留下警告,甚至发出警告。

重申一下,我的问题分为三部分:

  1. 我对警告原因的分析是否正确?
  2. 如何确定何时安全不调用类型的析构函数。换句话说,类型的析构函数何时完全没有效果,我如何检测它(使用类型特征等)?
  3. 这种检测是否始终可靠且完全可靠?

还有一个奖金问题:

我试过这个重载只是为了看它是否有用:

template <typename C>
std::enable_if<std::is_trivially_destructible<C>::value>
destroy (C *)
{
}

template <typename C>
std::enable_if<!std::is_trivially_destructible<C>::value>
destroy (C * c)
{
    c->~C ();
}

请注意,我并不是说使用std::is_trivially_destructible<>是要走的路;我只想尝试看看enable_if是否适用于此背景。但是现在我收到很多这样的错误:

error C2668: 'MyAlloc<Whatever>::destroy' : ambiguous call to overloaded function
could be 'std::enable_if<false,void> MyAlloc<Whatever>::destroy<SomeType>(C *)'
or       'std::enable_if<true,void> MyAlloc<Whatever>::destroy<SomeType>(C *)'

似乎我在做enable_if可怕的错误。我哪里错了?由于SFINAE,enable_if<false,...>替代品不应该从分辨率中删除吗? SFINAE也是在课堂上发生的吗?我也会感谢你在这方面的任何帮助。

c++ templates typetraits
3个回答
1
投票

我对警告原因的分析是否正确?

我认同。有几种方法可以静默一个未使用的变量警告(通常有特定的宏/函数来做这件事很有帮助)

如何确定何时安全不调用类型的析构函数。换句话说,类型的析构函数何时完全没有效果,我如何检测它(使用类型特征等)?

我会沉默警告。但如果我必须使用特征,我会使用std::is_trivially_destructible

这种检测是否始终可靠且完全可靠?

看起来并不完全,因为他们改变了C ++ 14的定义。

关于你的错误:

正确的语法是(注意typename .. ::type

template <typename C>
typename std::enable_if<std::is_trivially_destructible<C>::value>::type
destroy (C *){}

使用您的语法,您将返回存在的std::enable_if<std::is_trivially_destructible<C>::value>(因此它不会被SFINAE删除,然后您有两个相同的方法,具有不同的返回类型)

std::enable_if<bool condition, typename T>::type仅在条件为真时存在(并且等于默认为void的第二种类型)。


1
投票

Microsoft say it's a bug ("limitation") of their compiler

发明复杂的基于模板的变通方法是一项有趣的智力挑战,但在对真实产品进行代码审查时,我会把任何这样的事情扔得比你说的“过度工程”更快。

template <typename C>
void destroy (C * c) // <-- this is the 'c' that the warning is referring to
{
    (void)c; // shut up you stupid compiler
    c->~C ();
}

0
投票

关于1.缺少某些东西(代码/警告/错误消息)。

这很好用:

template <typename T>
void destroy(T* p) {
    p->~T();
}

int main()
{
    int* i;
    destroy(i);
    return 0;
}

用g ++编译-std = c ++ 11 -Wall -pedantic

© www.soinside.com 2019 - 2024. All rights reserved.