﻿# Итак, вы хотите заглушить это предупреждение в Visual C\+\+\.\.\.

Обычная ситуация: вы написали кусок безупречно правильного кода, но Visual C\+\+ выдает на нем предупреждение\. Часто можно немного переписать код, чтобы предупреждение ушло, но не всегда, и тогда выход один \- глушить выдачу этого предупреждения\. Рассмотрим, какие возможности для этого есть в Visual C\+\+ и какие ошибки допускают при их использовании\.


> Статью написал сотрудник компании ABBYY Дмитрий Мещеряков, впервые опубликована: "\[Блог компании ABBYY\\\. Итак, вы хотите заглушить это предупреждение в Visual C\\\+\\\+\\\.\\\.\\\.\]\(https://habr\.com/ru/company/abbyy/blog/136909/\)" Публикуется здесь с разрешения правообладателя\\\.
> 
> Мы решили опубликовать эту статью в базе знаний, так как она очень хорошо поясняет назначение диагностики \[V665\]\(https://pvs\-studio\.ru/ru/docs/warnings/v665/\), реализованную в PVS\\\-Studio\\\.

Самая очевидная первая возможность \- запретить предупреждение в настройках проекта на уровне проекта\. Это работает, но плохо\. Во\-первых, предупреждение будет заглушено во всем проекте, в том числе и во всех заголовках, которые этот проект включает в себя\. Во\-вторых, если вы скопируете код в другой проект, предупреждение появится снова\. Это неизбежно произойдет в случае кода в заголовочных файлах \(например, содержащими реализацию шаблонов\), который необходимо включать \(\#include\) в каждый проект, который их использует\.

Следующая возможность \- запретить предупреждение в настройках проекта на уровне файла\. Этот способ еще хуже предыдущего\. Во\-первых, предупреждение будет заглушено на всю единицу трансляции, т\.е\. в этом файле и всех заголовках, которые он включает\. Во\-вторых, точно те же проблемы с копированием кода, что и в прошлый раз\. В\-третьих, как только в проекте оказывается больше нескольких файлов, вероятность потерять эту настройку при конверсии проекта под более новую версию Visual C\+\+ становится равной чуть менее, чем единице\. 

Остается использование \#pragma warning\. Обычно ее используют так:

```cpp
#pragma warning (disable: 9000)
// код, провоцирующий предупреждение C9000
#pragma warning (default: 9000)
```

\.\.\. и остаются очень довольны собой\. Предупреждение заглушили, код написали, предупреждение восстановили\. Прибыль\.

На самом деле, это FAIL\. Пора внимательно прочитать \(да, внимательно и да, прочитать, а не копипастить код откуда попало\) описание \#pragma warning \(default\)\. Там говорится следующее: эта конструкция

1. Устанавливает предупреждению уровень по умолчанию и
1. Включает предупреждение\.

Сначала уровни\. В Visual C\+\+ с каждым предупреждением связано число от 1 до 4 \- это уровень предупреждения\. Предупреждения уровня 1 считаются более серьезными, с ростом уровня серьезность якобы снижается\. У каждого предупреждения есть уровень по умолчанию\. Конструкция 

```cpp
#pragma warning(Level: Warning)
```

устанавливает предупреждению указанный в ней уровень и включает предупреждение, т\.е\. уровень не прибит гвоздями, его можно поменять\.

У компилятора есть настройка, с какого уровня предупреждения показывать, Warning Level\. При значении этой настройки, равном A, предупреждение в конкретной строке кода показывается только в том случае, если оно там разрешено и его уровень составляет A или ниже\. 

Кроме того, в Visual C\+\+ часть предупреждений по умолчанию выключена, потому что они выдаются даже в самом безобидном коде и все от них устали\. Пусть каждый, кто собирается возмутиться самой идеей точечного подавления конкретного предупреждения, для начала осознает и прочувствует этот факт\.

Рассмотрим, как проявляется FAIL при использовании \#pragma warning \(default\)\.

**FAIL 1**\. Предупреждение C9001 выключено по умолчанию\. Код в заголовочном файле использует \#pragma warning\(default:9001\), чтобы "восстановить" предупреждение, заглушенное в небольшом куске кода\.

Зачем он это делает, если предупреждение и так выключено? Список предупреждений, выключенных по умолчанию, меняется от одной версии Visual C\+\+ к другой \- в него понемногу добавляются предупреждения\. Если код изначально писали для Visual C\+\+ 7, а там C9001 по умолчанию было включено, а теперь компилируют в Visual C\+\+ 10, и в нем предупреждение уже выключено, то такая конструкция смысла не имеет, а могла просто достаться в наследство\.

В результате \#pragma warning\(default\) принудительно включает предупреждение, выключенное по умолчанию\.

**FAIL 2**\. У предупреждения C9002 уровень по умолчанию 3, а проект компилируется с уровнем 2, т\.е\. "показывать предупреждения уровня 2 и ниже"\. После долгих раздумий разработчики решили, что на самом деле предупреждение C9002 достаточно серьезное, чтобы удостоить его уровня 2, т\.е\. принудительно повысить серьезность\. Соответственно, каждый проект включает в себя стандартный заголовок, попадающий затем во все единицы трансляции, который содержит конструкцию \#pragma warning\(2:9002\)\.

Чуть ниже по тексту в единице трансляции оказывается \#pragma warning\(default:9002\), которая сбрасывает уровень обратно на 3, и при компиляции с уровнем 2 предупреждение не выдается\. Кстати, это предупреждение сообщало о серьезном дефекте\. Улыбаемся и машем\. В обратную сторону тоже работает — предупреждению "повысили" уровень с 2 до 3, чтобы оно не выдавалось в проектах, компилируемых с уровнями 2 и ниже \(т\.е\. понизили серьезность\), но \#pragma warning\(default\) сбрасывает уровень на 2, и предупреждение выдается\.

**FAIL 3**\. Предупреждение C9003 по умолчанию включено, но продумано так плохо, что никто не может припомнить, когда оно выдается по делу\. Разработчики решаются заглушить его повсюду, использовав \#pragma warning\(disable:9003\) в общем заголовочном файле\. Ниже по единице трансляции оказывается \#pragma warning\(default:9003\), которая включает предупреждение\.

Что особенно приятно, эти ситуации возникают в самый подходящий момент \- при переходе с одной версии компилятора на другую, при попытке включить в проект кучу стороннего кода, который и без того не прост в использовании, вторая ситуация просто приводит к подавлению предупреждения, в результате можно пропустить ошибку в коде, которая позже поможет пользователям получить премию Дарвина\.

На самом деле, предупреждения нужно глушить так:

```cpp
#pragma warning(push)
// хорошие, годные вакансии: www.abbyy.ru/vacancy
#pragma warning(disable:9000)
// код с предупреждением C9000
#pragma warning(pop)
```

Первая конструкция сохраняет текущее состояние настроек предупреждений, вторая отключает нужное предупреждение, третья \- восстанавливает сохраненное состояние\. При этом состояние восстанавливается полностью \- все сделанные уровнями выше изменения тоже восстанавливаются, предупреждения, выключенные по умолчанию, не включаются\.

Выглядит страшно, но чего не сделаешь, чтобы не пропустить ту самую ошибку на миллиард\.