Я должен сказать, я думаю, что стиль глобального обработчика ошибок (с надлежащим локальным хранилищем потока) наиболее применим, когда невозможно использовать обработку исключений. Конечно, это не оптимальное решение, но я думаю, что если вы живете в моем мире (мире ленивых разработчиков, которые проверяют состояние ошибок не так часто, как следовало бы), это наиболее практично.
Обоснование: разработчики, как правило, не проверяют возвращаемые значения ошибок так часто, как следовало бы. Сколько примеров мы можем указать в реальных проектах, где функция возвратила некоторый статус ошибки только для вызывающего, чтобы игнорировать их? Или сколько раз мы видели функцию, которая даже не правильно возвращала статус ошибки, даже если она, скажем, выделяла память (что может привести к сбою)? Я видел слишком много подобных примеров, и возвращение и исправление их иногда могут даже потребовать масштабного проектирования или рефакторинга изменений в кодовой базе.
В этом отношении глобальный обработчик ошибок гораздо более прост:
Если функция не смогла вернуть логический тип или какой-либо тип ErrorStatus для указания сбоя, нам не нужно изменять его сигнатуру или тип возврата, чтобы указать сбой, и изменять код клиента во всем приложении. Мы можем просто изменить его реализацию, чтобы установить глобальный статус ошибки. Конечно, нам все еще нужно добавить проверки на стороне клиента, но если мы сразу пропустим ошибку на сайте вызова, все равно есть возможность ее отследить позже.
Если клиенту не удается проверить состояние ошибки, мы все равно можем обнаружить ошибку позже. Конечно, ошибка может быть перезаписана последующими ошибками, но у нас все еще есть возможность увидеть, что ошибка произошла в какой-то момент, тогда как вызывающий код, который просто игнорировал возвращаемые значения ошибки на сайте вызова, никогда не допустил бы ошибку будет замечен позже.
Будучи неоптимальным решением, если обработка исключений не может быть использована, и мы работаем с командой обезьян, которые имеют ужасную привычку игнорировать возвращаемые значения ошибок, это наиболее практичное решение, поскольку как я вижу.
Конечно, обработка исключений с надлежащей безопасностью исключений (RAII) - безусловно, лучший метод здесь, но иногда обработка исключений не может быть использована (например: мы не должны выбрасывать за пределы модуля). В то время как глобальный обработчик ошибок, такой как GetLastError API Win * или glGetError OpenGL, звучит как устаревшее решение со строгой инженерной точки зрения, гораздо проще простить модернизацию системы, чем начинать делать все возвращают некоторый код ошибки и начинают заставлять все вызывающие эти функции проверять их.
Однако, если этот шаблон применяется, необходимо внимательно следить за тем, чтобы он мог правильно работать с несколькими потоками и без значительных потерь производительности. Для этого мне пришлось спроектировать собственную систему локального хранилища потоков, но наша система преимущественно использует обработку исключений и только этот глобальный обработчик ошибок для преобразования ошибок через границы модуля в исключения.
В общем, обработка исключений - это путь, но если по какой-то причине это невозможно, я вынужден не согласиться с большинством ответов здесь и предложить что-то вроде GetLastError для более крупных и менее дисциплинированных команд (я Можно сказать, возвращать ошибки через стек вызовов для меньших, более дисциплинированных) на том основании, что, если возвращаемый статус ошибки игнорируется, это позволяет нам, по крайней мере, заметить ошибку позже, и это позволяет нам преобразовать обработку ошибок в функция, которая не была должным образом разработана для возврата ошибок путем простого изменения ее реализации без изменения интерфейса.