Выбрасывание исключений в C ++ игра DLL? За и против

Каковы профи и минус использования Исключений в C ++ в отношении разработки игр.

В руководстве по стилю Google говорится, что они не используют исключения по разным причинам. Имеются ли те же причины, которые имеют отношение к развитию игры?

  

Мы не используем исключения C ++ ... - google-styleguide.googlecode.com

Некоторые проблемы, о которых нужно подумать.

  • Как это относится к разработке библиотек, используемых в нескольких проектах.
  • Как это влияет на модульное тестирование, интеграционное тестирование и т. д.
  • Что он делает для использования сторонних библиотек.
9 голосов | спросил David Young 15 AM000000120000001631 2010, 00:05:16

7 ответов


7

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

Например, в C ++ бросание исключения в деструкторе может иметь серьезные последствия. Это может вызвать все виды неопределенного поведения и сбоев, поскольку вы можете попасть в ловушку в ситуации, когда в полете имеется более одного активного исключения. (Дополнительную информацию об этом см. В разделе № 8 Эффективный C ++ .)

ответил Bob Somers 15 AM00000050000005131 2010, 05:14:51
8

Представления Joel on Software об исключениях.

Интересный вид в настоящий момент не отвечает ни на один из ответов,

  

Мы считаем, что исключения не лучше, чем «goto's», которые считаются вредными с 1960-х годов, поскольку они создают резкий переход от одной точки кода к другой. На самом деле они значительно хуже, чем goto's:

     
  1. Они невидимы в исходном коде. Глядя на блок кода, включая функции, которые могут или не могут генерировать исключения, нет способа увидеть, какие исключения могут быть выбраны и откуда. Это означает, что даже тщательная проверка кода не выявляет потенциальных ошибок.

  2.   
  3. Они создают слишком много возможных точек выхода для функции. Чтобы написать правильный код, вам действительно нужно думать о каждом возможном пути кода через вашу функцию. Каждый раз, когда вы вызываете функцию, которая может вызвать исключение и не поймать ее на месте, вы создаете возможности для неожиданных ошибок, вызванных функциями, которые внезапно прекратились, оставив данные в несогласованном состоянии или другие пути кода, которые вы не сделали подумайте.

  4.   

http://www.joelonsoftware.com/items/2003/10/13.html

ответил David Young 15 PM00000030000003931 2010, 15:24:39
5

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

Большинство разработчиков консоли, которых я знаю, предпочитают не использовать их в любом случае из-за дополнительных накладных расходов в исполняемом файле и философии, что они просто не нужны. RTTI просматривается одинаково.

ответил Dan Olson 15 AM00000060000000631 2010, 06:30:06
2

Из всех проектов, над которыми я работал в играх, ни один из них не использовал исключения. Основная накладная - вызов функции. Как упоминалось ранее, как и RTTI, в большинстве студий это не предмет обсуждения. Не потому, что большинство кодировщиков исходят из опыта Java /academics, потому что, честно говоря, большинство не делают. Это не влияет на модульное тестирование, поскольку вы просто утверждаете на условиях. Для библиотек вам лучше без исключений, так как вы будете вынуждать их на всех, кто ее использует.
Несмотря на то, что некоторые ситуации немного сложнее обрабатывать, он также (imo) заставляет вас иметь более контролируемую настройку, поскольку исключения могут привести к злоупотреблениям. Допуск ошибок - это хорошо, но нет, если это приведет к неаккуратной кодировке.
Имейте в виду, что это происходит от тех, кто никогда не использовал обработку исключений (хорошо, один раз или два раза в инструментах - он не сделал этого для меня, я думаю, это то, с чем вы выросли).

ответил Kaj 15 AM00000080000003731 2010, 08:56:37
1

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

В исключениях нет ничего неправильного, просто они не хороши, потому что реальность мешает теории.

ответил Richard Fabian 17 PM00000030000002931 2010, 15:31:29
0

Для меня обработка исключений может быть отличной, если все соответствует RAII, и вы резервируете исключения для действительно исключительных путей (например: поврежденный файл, который читается), и вам никогда не нужно бросать границы модулей, и вся ваша команда находится на доска с ними ......

Нулевая стоимость EH

Большинство компиляторов в наши дни реализуют обработку исключений с нулевой стоимостью, что может сделать ее еще более дешевой, чем ручное разветвление на условиях ошибки в обычных путях выполнения, хотя взамен она делает исключительные пути чрезвычайно дорогими (есть и некоторый раздутый код от него, хотя вероятно, не больше, чем если бы вы полностью обрабатывали каждую возможную ошибку вручную). Тот факт, что бросание чрезвычайно дорого, не имеет значения, если исключения используются так, как они предназначены на C ++ (для действительно исключительных обстоятельств, которые не должны происходить в нормальных условиях).

Сдвиг бокового эффекта

Тем не менее, все, что соответствует RAII, гораздо легче сказать, чем сделать. Легко локализованные ресурсы, хранящиеся в функции, для их переноса на объекты C ++ с деструкторами, которые очищают себя, но не так просто написать логику отмены /отката для каждого побочного эффекта, который может возникнуть во всем программном обеспечении. Просто подумайте, как трудно написать контейнер, например std::vector, который является самой простой последовательностью случайного доступа, чтобы быть абсолютно безопасным для исключений. Теперь умножьте эту трудность на все структуры данных всего крупномасштабного программного обеспечения.

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

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

Там что-то практически не так, потому что концептуальное разворот побочных эффектов - сложная проблема, но на C ++ это осложнилось. На самом деле проще иногда обращать побочные эффекты в C в ответ на код ошибки, чем это делать в ответ на исключение в C ++. Одна из причин заключается в том, что любая данная точка любой функции может потенциально throw в C ++. Если вы пытаетесь написать общий контейнер, работающий с типом T, вы даже не можете ожидать, где эти точки выхода, поскольку все с помощью T может выбраться. Даже сравнение одного T с другим для равенства может бросить. Ваш код должен обрабатывать каждую возможность , а число возможностей умножается экспоненциально в C ++, тогда как в C их намного меньше.

Отсутствие стандартов

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

Должны быть некоторые более разумные стандарты, такие как никогда не бросать из оператора сравнения (все функции, которые логически неизменяемы никогда не должны бросать), никогда не бросать из движения ctor и т. д. Такие гарантиисделало бы намного проще писать исключающий код код, но у нас нет таких гарантий. Мы должны придерживаться правила, которое все может бросить - если не сейчас, то, возможно, в будущем.

Хуже того, люди из разных языков смотрят на исключения по-разному. В Python у них действительно есть эта «прыжок перед тем, как вы смотрите», которая включает в себя запуск исключений в обычных путях выполнения! Когда вы получаете таких разработчиков, которые пишут код на C ++, вы можете смотреть на исключения, которые бросаются влево и вправо для вещей, которые на самом деле не являются исключительными, а обработка всего этого может быть кошмаром, если вы пытаетесь написать общий код, например

Ошибка обработки

Обработка ошибок имеет тот недостаток, что вы должны проверить все возможные ошибки, которые могут возникнуть. Но у него есть одно преимущество: иногда вы можете немного проверить ошибки, опаздывая, например glGetError, чтобы значительно уменьшить точки выхода в функции, а также сделать их явными. Иногда вы можете продолжать работать с кодом немного дольше, прежде чем проверять и распространять и восстанавливать ошибку, а иногда это может быть проще, чем обработка исключений (особенно с отменой побочных эффектов). Но вы даже не можете так много беспокоиться об ошибках в игре, может быть, просто отключите игру с сообщением, если столкнулись с такими вещами, как поврежденные файлы, ошибки в памяти и т. Д.

  

Как это относится к разработке библиотек, используемых через   несколько проектов.

Отвратительная часть исключений в контексте DLL заключается в том, что вы не можете безопасно перебрасывать исключения из одного модуля в другой, если не можете гарантировать, что они созданы одним и тем же компилятором, используют те же настройки и т. д. Поэтому, если вы пишете как плагиновую архитектуру, предназначенную для людей, которые могут использоваться из всех видов компиляторов и, возможно, даже с разных языков, таких как Lua, C, C #, Java и т. д., часто исключения становятся серьезной неприятностью, поскольку вы должны проглатывать каждое исключение и переводить их кодам ошибок в любом случае повсюду.

  

Что он делает для использования сторонних библиотек.

Если они являются дилибами, то они не могут безопасно выбрасывать исключения по причинам, упомянутым выше. Им придется использовать коды ошибок, которые также означают, что вы, используя библиотеку, должны постоянно проверять коды ошибок. Они могли бы обернуть их dylib статически связанной C ++-оболочкой lib, которую вы создаете самостоятельно, что переводит коды ошибок из dylib в заброшенные исключения (в основном бросая из вашего двоичного кода в ваш двоичный файл). В общем, я думаю, что большинство сторонних библиотек не должны даже беспокоиться и просто придерживаться кодов ошибок, если они используют dylibs /shared libs.

  

Как это влияет на модульное тестирование, интеграционное тестирование и т. д.

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

Любовь /Ненависть

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

Они были бы экспоненциально более полезными для меня, если бы стандартный комитет действительно сосредоточил свое внимание на установлении стандартов ABI, которые позволили бы исключать исключения из модулей, по крайней мере, с C ++ на C ++. Было бы здорово, если бы вы могли спокойно перебросить языки, хотя это своего рода мечта о трубе. Другая вещь, которая сделала бы исключения экспоненциально более полезными для меня, - это если функции noexcept фактически вызвали ошибку компилятора, если они пытались вызвать любую функциональность, которая вместо вызова std::terminate может возникнуть вызов исключения. Это рядом с бесполезным (может также назвать, что icantexcept вместо noexcept). Было бы намного проще обеспечить, чтобы все деструкторы были безопасны для исключения, например, если noexcept фактически вызвал ошибку компилятора, если деструктор делал все, что мог бросить. Если это слишком дорого для тщательного определения во время компиляции, то просто сделайте так, чтобы функции noexcept (которые должны были быть все деструкторы) разрешено также вызвать функции noexcept /операторы и сделать ошибку компилятора для выброса из любого из них.

ответил 8 Jam1000000amMon, 08 Jan 2018 00:54:50 +030018 2018, 00:54:50
-2

Насколько я вижу, есть две основные причины, по которым это традиционно не используется в разработке игр:

  • Большинство программистов - выпускники, которые изучали Java и Haskell, или программисты C, у которых нет опыта исключений. Поэтому они довольно боятся их и не знают, как правильно их использовать.
  • Сбрасывание стека, когда генерируется исключение, имеет последствия для производительности (хотя это своего рода полученная мудрость, и некоторые ссылки были бы замечательными).
ответил tenpn 15 AM000000120000000831 2010, 00:57:08

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132