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

yzt*_*yzt 5 c++ templates type-traits

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

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

warning C4100: 'c' : unreferenced formal parameter
Run Code Online (Sandbox Code Playgroud)

在这个方法中:

template <typename T>
class MyAlloc
{
    ...

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

    ...
};
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,警告和代码都非常简单明了。在我看来,发出警告是因为该分配器所使用的某些类没有析构函数(例如,因为它们是 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 ();
}
Run Code Online (Sandbox Code Playgroud)

请注意,我并不是说使用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 *)'
Run Code Online (Sandbox Code Playgroud)

看来我正在做一些非常错误的事情enable_if。我哪里错了?难道不应该enable_if<false,...>因为 SFINAE 而从决议中删除替代方案吗?SFINAE 也在课堂范围内发生吗?我也将感谢在这方面的任何帮助。

Jar*_*d42 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 *){}
Run Code Online (Sandbox Code Playgroud)

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

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