简体   繁体   English

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

[英]Detecting When a Type Doesn't Need Calling Its Destructor

I'm writing a C++11 STL-compatible allocator, and I was wondering how to detect the types for which it is safe not to call their destructor (in allocator<T>::destroy method.) 我正在编写一个C ++ 11 STL兼容的分配器,我想知道如何检测安全的类型, 不要调用它们的析构函数(在allocator<T>::destroy方法中)。

I have already written the allocator (a simple one) and as far as I can tell, it does work. 我已经编写了分配器(一个简单的分配器),据我所知,它确实有效。 The reason I ask is that I'm getting warnings in my code (ie in the destroy method of my allocator.) I'm using VS2013 (vc12) at the highest warning level, and the warning is: 我问的原因是我在我的代码中收到警告(即在我的分配器的destroy方法中。)我在最高警告级别使用VS2013(vc12),警告是:

warning C4100: 'c' : unreferenced formal parameter

in this method: 在这个方法中:

template <typename T>
class MyAlloc
{
    ...

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

    ...
};

As you can see, both the warning and the code are pretty simple and straightforward. 如您所见,警告和代码都非常简单明了。 It seems to me that the warning is issued because some of the classes that this allocator gets used for don't have destructors (eg because they are POD, etc.) Subsequently, the compiler removes the call to the destructor in the above function when the allocator is being instantiated for such classes and then, seeing that the function body is empty and the argument is unused, issues the warning. 在我看来发出警告是因为这个分配器使用的一些类没有析构函数(例如因为它们是POD等)。随后,编译器在上面的函数中删除了对析构函数的调用。正在为这些类实例化分配器,然后,看到函数体为空且参数未使用,则发出警告。

I'm thinking that I can write two versions of the above destroy method, overloading using enable_if , and leaving the body empty and the argument unnamed in the overload that is for classes that don't need destruction. 我想我可以编写上面的destroy方法的两个版本,使用enable_if重载,并将主体保留为空,并且在重载中未命名的参数是不需要破坏的类。 Would this work? 这会有用吗?

On the other hand, this warning is a very small inconvenience. 另一方面,这个警告是一个非常小的不便。 I can disable this particular warning, and it won't have much impact on my codebase. 我可以禁用此特定警告,它对我的​​代码库没有太大影响。 After all, this is hardly a useful warning. 毕竟,这不是一个有用的警告。

However, if I do try to change my code and detect classes that don't need destruction, but do it unreliably and poorly, I open the floodgates for all sorts of pain and suffering. 但是,如果我确实尝试更改我的代码并检测不需要破坏的类,但是做得不可靠和糟糕,我会为各种各样的痛苦和痛苦打开闸门。 Because if I happen to not destruct an instance of a class that does need destruction, only the gods know what can (and would) go wrong! 因为如果我碰巧没有破坏一个确实需要破坏的类的实例,只有众神知道什么可以(并且会)出错! So, if there isn't a 100% reliable and robust method to detect such classes and handle them, I prefer to leave in the warning and even ship with the warning. 因此,如果没有100%可靠且稳健的方法来检测这些类并处理它们,我更愿意留下警告,甚至发出警告。

To reiterate, my question is in three parts: 重申一下,我的问题分为三部分:

  1. Is my analysis of the cause of the warning correct? 我对警告原因的分析是否正确?
  2. How can I determine when it is safe not to call a type's destructor. 如何确定何时安全不调用类型的析构函数。 In other words, when does a type's destructor has absolutely no effect and how can I detect this (using type traits, etc.)? 换句话说,类型的析构函数何时完全没有效果,我如何检测它(使用类型特征等)?
  3. Is this detection always reliable and completely robust? 这种检测是否始终可靠且完全可靠?

And a bonus question: 还有一个奖金问题:

I tried this overload just to see whether it'd work: 我试过这个重载只是为了看它是否有用:

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 ();
}

Note that I'm not saying that using std::is_trivially_destructible<> is the way to go; 请注意,我并不是说使用std::is_trivially_destructible<>是要走的路; I just wanted to try and see whether enable_if works in this context. 我只想尝试看看enable_if是否适用于此上下文。 But now I'm getting many errors like this: 但是现在我收到很多这样的错误:

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 *)'

Seems I'm doing something horribly wrong with enable_if . 似乎我在使用enable_if做了一些可怕的错误。 Where am I going wrong? 我哪里错了? Shouldn't the enable_if<false,...> alternate be dropped from resolution due to SFINAE? 由于SFINAE enable_if<false,...>不应该从分辨率中删除enable_if<false,...> alternate? Does SFINAE happen at class scope as well? SFINAE也是在课堂上发生的吗? I'll be thankful for any help in this regard as well. 我也会感谢你在这方面的任何帮助。

Is my analysis of the cause of the warning correct? 我对警告原因的分析是否正确?

I think so. 我认同。 There are several ways to silent an unused variable warning (and generally having specific macro/function to do that is helpful) 有几种方法可以静默一个未使用的变量警告(通常有特定的宏/函数来做这件事很有帮助)

How can I determine when it is safe not to call a type's destructor. 如何确定何时安全不调用类型的析构函数。 In other words, when does a type's destructor has absolutely no effect and how can I detect this (using type traits, etc.)? 换句话说,类型的析构函数何时完全没有效果,我如何检测它(使用类型特征等)?

I would silent the warning. 我会沉默警告。 but if I have to use traits, I would use std::is_trivially_destructible . 但如果我必须使用特征,我会使用std::is_trivially_destructible

Is this detection always reliable and completely robust? 这种检测是否始终可靠且完全可靠?

Seem not fully as they change the definition for C++14. 看起来并不完全,因为他们改变了C ++ 14的定义。

About your error: 关于你的错误:

The correct syntax is (note the typename .. ::type ) 正确的语法是(注意typename .. ::type

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

With your syntax, you return std::enable_if<std::is_trivially_destructible<C>::value> which exists (so it is not removed by SFINAE and then you have two identical methods with different return types) 使用您的语法,您将返回存在的std::enable_if<std::is_trivially_destructible<C>::value> (因此它不会被SFINAE删除,然后您有两个具有不同返回类型的相同方法)

std::enable_if<bool condition, typename T>::type only exists when the condition is true (and is equal to the second type defaulted to void ). std::enable_if<bool condition, typename T>::type仅在条件为true时存在(并且等于第二个默认为void类型)。

Microsoft say it's a bug ("limitation") of their compiler . 微软称这是他们编译器的一个错误(“限制”)

Inventing complex template-based workarounds is an interesting intellectual challenge, but in a code review for a real product I would throw any such thing away faster than you can say "overengineered". 发明复杂的基于模板的变通方法是一项有趣的智力挑战,但在对真实产品进行代码审查时,我会把任何这样的事情扔得比你说的“过度工程”更快。

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 ();
}

Regarding 1. Something is missing (code/warnings/error messages). 关于1.缺少某些东西(代码/警告/错误消息)。

This works just fine: 这很好用:

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

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM