Симон Моурир дал этот пример :
object o = null;
DateTime d = (DateTime)o; // NullReferenceException
, где unboxing преобразование (литье) из object
(или из одного из классов System.ValueType
или System.Enum
или из типа интерфейса) - тип значения (кроме Nullable<>
) сам по себе дает NullReferenceException
.
В другом направлении конверсия бокса из a Nullable<>
, которая имеет HasValue
, равную false
, на ссылочный тип, может дать ссылку null
, которая затем может привести к NullReferenceException
. Классический пример:
DateTime? d = null;
var s = d.ToString(); // OK, no exception (no boxing), returns ""
var t = d.GetType(); // Bang! d is boxed, NullReferenceException
Иногда бокс происходит по-другому. Например, с помощью этого не общего метода расширения:
public static void MyExtension(this object x)
{
x.ToString();
}
следующий код будет проблематичным:
DateTime? d = null;
d.MyExtension(); // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.
Эти случаи возникают из-за специальных правил, используемых во время выполнения при боксе Nullable<>
экземпляров.
Это не автоматическое, но Doxygen создаст диаграммы зависимостей для # включенных файлов. Вам придется пройти через них визуально, но они могут быть очень полезны для получения изображения того, что использует.
Также проверьте include-what-you-use , который решает подобную проблему.
Чтобы завершить это обсуждение, препроцессор c ++ завершен. Это семантическое свойство, независимо от того, является ли включение излишним. Следовательно, из теоремы Райса следует, что неразрешимо, является ли включение избыточным или нет. Там НЕ МОЖЕТ быть программа, которая (всегда правильно) определяет, является ли добавление излишним.
Вот простой способ для перебора лишнего заголовка включает . Это не идеально, но устраняет «очевидные» ненужные включения.
Я пробовал использовать Flexelint (unix-версия PC-Lint) и имел несколько смешанные результаты. Скорее всего, потому, что я работаю над очень большой и узловатой базой кода. Я рекомендую внимательно изучить каждый файл, который сообщается как неиспользованный.
Основное беспокойство - ложные срабатывания. Несколько включений одного и того же заголовка сообщаются как ненужный заголовок. Это плохо, потому что Flexelint не сообщает вам, в какую строку заголовок включен или где он был включен ранее.
Один из способов, по которому автоматические инструменты могут ошибиться:
В A .hpp:
class A {
// ...
};
В B.hpp:
#include "A.hpp
class B {
public:
A foo;
};
В C.cpp:
#include "C.hpp"
#include "B.hpp" // <-- Unneeded, but lint reports it as needed
#include "A.hpp" // <-- Needed, but lint reports it as unneeded
Если вы слепо следуете сообщениям из Flexelint вы отбросите свои зависимости #include. Есть больше патологических случаев, но в основном вам нужно будет проверить заголовки самостоятельно для достижения наилучших результатов.
Я очень рекомендую эту статью о Physical Structure и C ++ из блога Игры изнутри. Они рекомендуют комплексный подход к очистке #include mess:
Рекомендации
Вот дистиллированный набор рекомендаций из книги Lakos, который сводит к минимуму количество физических зависимостей между файлами , Я использую их в течение многих лет, и я всегда был очень доволен результатами.
blockquote>
- Каждый файл cpp включает в себя собственный заголовочный файл. [snip]
- Заголовочный файл должен содержать все файлы заголовков, необходимые для его анализа. [snip]
- В файле заголовка должно быть минимальное количество файлов заголовков, необходимых для его анализа. [snip]
Существует два типа избыточных файлов #include:
В моем опыте есть два способа:
Gimpel Software PC Lint может сообщать, когда включенный файл был включен более одного раза в блок компиляции, но он не может найти файлы, которые не нужны в том, как вы смотрите для.
Изменить: Он может. См. Ответ itsmatt
CLion , C / C ++ IDE из JetBrains, обнаруживает избыточность, включает в себя готовые. Они выделены серым цветом в редакторе, но функции optimize включают в текущий файл или весь проект .
Я обнаружил, что вы платите за эту функциональность, хотя ; CLION требует времени для сканирования и анализа вашего проекта при первой загрузке.
Извините, что (пере) сообщение здесь, люди часто не раздают комментарии.
Проверьте мой комментарий на crashmstr, FlexeLint / PC-Lint сделает это за вас. Информационное сообщение 766. В этом разделе обсуждается раздел 11.8.1 моего руководства (версия 8.0).
Кроме того, и это важно, продолжайте повторять, пока сообщение не исчезнет. Другими словами, после удаления неиспользуемых заголовков повторно запустите lint, после того, как вы удалите ненужные заголовки, больше файлов заголовков могут стать «ненужными». (Это может показаться глупым, медленно прочитайте его и проанализируйте его, это имеет смысл.)
Я никогда не нашел полноценного инструмента, который выполняет то, что вы просите. Самая близкая вещь, которую я использовал, - IncludeManager , которая отображает ваше дерево включения заголовка, чтобы вы могли визуально распознавать такие вещи, как заголовки, включенные только в один файл и включения круговых заголовков.
Браузер рефакторинга CScout может обнаруживать избыточные директивы include в коде C (к сожалению, не C ++). Вы можете найти описание того, как это работает в этой статье журнала .
Вы можете написать быстрый скрипт, который удаляет единственную директиву #include, компилирует проекты и записывает имя в #include и файл, из которого он был удален, в случае, если ошибки компиляции не были.
Пусть он работает ночью, а на следующий день у вас будет 100% правильный список включенных файлов, которые вы можете удалить.
Иногда грубая сила работает: -)
edit: а иногда это не так :-). Вот немного информации из комментариев:
Я думал, что PCLint сделает это, но прошло несколько лет с тех пор, как я посмотрел на него. Вы можете проверить это.
Я просмотрел этот блог , и автор немного рассказал о настройке PCLint, чтобы найти неиспользованные. Возможно, стоит посмотреть.
Проблема с обнаружением избыточных включает в себя то, что она не может быть просто средством проверки зависимостей типа. Неверный include - это файл, который не дает ничего полезного для компиляции и не изменяет другой элемент, от которого зависят другие файлы. Существует много способов, которыми файл заголовка может изменять компиляцию, например, определяя константу, переопределяя и / или удаляя используемый макрос, добавляя пространство имен, которое изменяет поиск имени каким-либо образом вниз по строке. Чтобы обнаружить такие элементы, как пространство имен, вам нужно гораздо больше, чем препроцессор, вам фактически нужен полный компилятор.
Lint - это скорее средство проверки стиля и, конечно же, не будет иметь этой полной возможности.
Я думаю, вы обнаружите, что единственный способ обнаружить избыточное включение - это удаление, компиляция и запуск наборов.
Google cppclean (ссылки на: скачать , documentation ) может найти несколько категорий проблем C ++, и теперь он может найти лишние #includes.
Также есть инструмент, основанный на Clang, include-what-you-use , который может это сделать. include-what-you-use может даже предлагать передовые декларации (так что вам не нужно так много #include) и, возможно, очистите свои #includes для вас.
В текущих версиях Eclipse CDT также встроена эта функциональность: перейдите в меню «Источник» и нажмите «Упорядочить» включит в алфавитном порядке ваши # include, добавьте заголовки, которые Eclipse думает, что вы используя без прямого их включения, и комментирует любые заголовки, которые, по вашему мнению, вам не нужны. Однако эта функция не на 100% надежна.
Если вы используете Eclipse CDT, вы можете попробовать http://includator.com , который бесплатно для бета-тестеров (на момент написания этой статьи) и автоматически удаляет лишние #includes или добавляет недостающие , Для тех пользователей, которые имеют FlexeLint или PC-Lint, и используют Elitpse CDT, http://linticator.com может быть вариантом (также бесплатным для бета-теста). Хотя он использует анализ Lint, он обеспечивает быстрые исправления для автоматического удаления лишних операторов #include.
Возможно, немного поздно, но однажды я нашел скрипт Perl WebKit, который сделал именно то, что вы хотели. Мне нужно немного адаптироваться (я не очень разбираюсь в perl), но он должен сделать трюк:
(это старая ветка, потому что у trunk больше нет файла)
В этой статье объясняется метод #include удаления с использованием разбора Doxygen. Это всего лишь скрипт perl, поэтому он довольно прост в использовании.
Существует бесплатный инструмент Include File Dependencies Watcher , который можно интегрировать в визуальную студию. Он показывает лишние # включает красный.