2014-01-06 1 views
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. Где я иду не так? Не следует ли исключить альтернативу enable_if<false,...> из резолюции из-за SFINAE? Идет ли SFINAE в классе? Я также буду благодарен за любую помощь в этом отношении.

+1

Правильный синтаксис 'шаблон имяТипа станд :: enable_if <станд :: is_trivially_destructible :: значение> :: тип уничтожить (C *) {}' – Jarod42

+0

станд :: has_virtual_destructor также может быть полезно? – hevi

+0

@hevi: У многих типов нет (и на самом деле не нужны) виртуальные деструкторы, но у них все еще есть нетривиальные деструкторы, которые должны быть вызваны. – yzt

ответ

1

Is my analysis of the cause of the warning correct?

думаю. Есть несколько способов бесшумного неиспользуемое переменное предупреждения (и, как правило, имеющие конкретные макро/функция, чтобы сделать это полезно)

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.)?

я бы молчал предупреждение. , но если мне нужно использовать черты, я бы использовал std::is_trivially_destructible.

Is this detection always reliable and completely robust?

Похоже, что они не изменяют определение для C++ 1y.

About your error:

Правильный синтаксис (обратите внимание на 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).

0

Относительно 1. Что-то не хватает (код/​​предупреждения/сообщения об ошибках).

Это работает просто отлично:

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

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

Собран с г ++ -std = C++ 11 -Wall -pedantic

+0

У меня нет доступа к VS, чтобы проверить прямо сейчас, но вы построили это на самом высоком уровне предупреждения? – yzt

+0

Возможно, GCC достаточно умен, чтобы не жаловаться, но VC нет. В этом случае предупреждение исчезло после того, как я правильно выполнил трюк 'enable_if'. – yzt

1

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

Изобретение комплексных обходных решений на основе шаблонов является интересным интеллектуальным вызовом, но в обзоре кода для реального продукта я бы выбросил любую такую ​​вещь быстрее, чем вы можете сказать «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(); 
} 
+0

Спасибо за ссылку. Мне не приходилось проверять официальную документацию friggin! Я тоже думаю, что молчание предупреждения здесь является гораздо более мудрым выбором. – yzt