Руководство по стилю Google С++. Правила исключения исключений; STL?

Google Руководство по стилю на С++ говорит: "Мы не используем исключения". Стиль не упоминает STL в отношении использования исключения. Поскольку распределители STL могут терпеть неудачу, как они обрабатывают исключения, создаваемые контейнерами?

  • Если они используют STL, как вызывающий абонент узнает о сбоях распределения? Методы STL, такие как push_back() или map operator[], не возвращают коды статуса.
  • Если они не используют STL, какую реализацию контейнера они используют?

Ответ 1

Говорят, что они не используют исключения, а не то, что их никто не должен использовать. Если вы посмотрите на обоснование, которое они также пишут:

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

Обычная устаревшая проблема.: - (

Ответ 2

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

Я работал инженером в Google Поиске на С++ с 2008 года. Мы часто используем контейнеры STL. Я лично не могу вспомнить ни одного серьезного сбоя или ошибки, которая когда-либо была прослежена до чего-то вроде vector:: push_back() или map:: operator [] с ошибкой, где мы сказали "о человеке, мы должны переписать этот код, потому что распределение могло fail" или "dang, если бы мы использовали исключения, этого можно было бы избежать". Есть ли когда-нибудь закончившийся процесс? Да, но это, как правило, простая ошибка (например, кто-то добавил в программу большой новый файл данных и забыл увеличить выделение ОЗУ) или катастрофический сбой, когда нет хорошего способа восстановить и продолжить. Наша система уже управляет и перезапускает задания автоматически, чтобы быть надежными для машин с неисправными дисками, космическими лучами и т.д., И это действительно не так.

Итак, насколько я могу судить, здесь нет проблем.

Ответ 3

Я уверен, что они подразумевают, что они не используют исключения в их. Если вы посмотрите их cpplint script, он проверяет, чтобы вы включали правильные заголовки для контейнеров STL (например, вектор, список и т.д.).

Ответ 4

Я обнаружил, что Google упоминает это явно о STL и исключениях (акцент мой):

Хотя вы не должны использовать исключения в своем собственном коде, они используются широко в ATL и некоторых STL, включая тот, который приходит с Visual С++. При использовании ATL вы должны определить _ATL_NO_EXCEPTIONS, чтобы отключить исключения. Вы должны выяснить, вы также можете отключить исключения в своем STL, но если нет, ОК, чтобы включить исключения в компиляторе. (Заметим, что это только для получить STL для компиляции. Вы все равно не должны писать обработку исключений код самостоятельно.)

Мне не нравятся такие решения (мне повезло, что я не работаю в Google), но они совершенно поняли их поведение и намерения.

Ответ 5

Вы не можете справиться с откатом в распределении ресурсов в современных операционных системах; как оптимизация производительности, они обычно перегружают память. Например, если вы вызываете malloc() и запрашиваете действительно огромный кусок памяти в Linux, это будет успешным, даже если память, необходимая для его поддержки, на самом деле там не существует. Его единственный, когда вы обращаетесь к нему, что ядро ​​на самом деле пытается выделить страницы для его поддержки, и в этот момент слишком поздно сказать вам, что распределение все равно не удалось.

Итак:

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

  • Тем не менее, его хорошая практика заключается в том, чтобы поймать необработанные исключения и записать вывод e.what(), а затем rec throw, поскольку это может быть более информативным, чем обратная трассировка, а типичные реализации библиотеки С++ не делают это автоматически для вы.

  • Вся огромная нить выше о том, как вы не можете полагаться на сбой, когда у вас заканчивается память, является полным и полным мусором. Стандарт C (++) может не гарантировать этого, но на современных системах сбой - это единственное, на что вы можете положиться, если у вас закончилась нехватка памяти. В частности, вы не можете полагаться на получение NULL или даже любых других указаний от вашего распределителя, вплоть до исключения С++.

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

Я получу квалификацию выше, заявив, что это возможно, если вы используете какой-то пользовательский распределитель или что youre в системе, которая не перехватывает (встроенные системы без свопа - один из примеров этого, но не единственный пример). В этом случае, может быть, вы можете обработать из-за нехватки памяти условия в вашей системе. Но в целом в 21 веке я боюсь, что вы вряд ли получите шанс; первое, что вы знаете, что ваша система не в памяти, - это когда все начинает сбой.

Ответ 6

Сам Stl непосредственно бросается только в случае сбоя выделения памяти. Но обычно приложение реального мира может потерпеть неудачу по разным причинам, а отказ в распределении памяти - только один из них. В случае 32-разрядной системы отказ в распределении памяти не является чем-то, что следует игнорировать, поскольку это может произойти. Таким образом, вся дискуссия выше, что неудача выделения памяти не будет происходить, совершенно бессмысленно. Даже предполагая это, нужно написать один код, используя двухэтапную инициализацию. И обработка исключений С++ предшествует 64-разрядным архитектурам в течение длительного времени. Я не уверен, как далеко я должен уделить должное отрицательному профессионализму, показанному здесь google, и только ответить на заданный вопрос. Я помню несколько статей из IBM примерно в 1997 году о том, насколько хорошо некоторые люди в IBM поняли и оценили последствия С++ Exception Handling. Хороший профессионализм не нужен показатель успеха. Поэтому отказ от обработки исключений - это не только проблема, если вы используете STL. Это проблема, если использовать С++ как таковой. Это означает отказ от

  • отказ конструктора
  • возможность использования объектов-членов и объектов базового класса в качестве аргументов для любого из следующих конструкторов класса base/member (без какого-либо тестирования). Неудивительно, что люди использовали двухэтапную конструкцию до того, как существовала обработка исключений С++.
  • отказ от иерархических и насыщенных сообщений об ошибках в среде, которая позволяет обеспечить предоставление кода клиентами или третьими лицами, а также ошибки сбрасывания, которые, по-видимому, невозможно было записать оригинальному писателю вызывающего кода при написании вызывающего кода, и предоставили место для кода возврата кода ошибки.
  • избегает таких хаков, как возврат указателя на объект статической памяти на отказ при рассылке сообщения, который авторы FlexLm сделали
  • возможность использовать распределитель памяти, возвращающий адреса в разрешенный файл с отображением памяти. В этом случае отказ в распределении происходит, когда один обращается к рассматриваемой памяти. (Ok в настоящее время это работает только на окнах, но яблоко вынудило команду gnu предоставить необходимую функциональность в компиляторе g++. Еще одно давление со стороны разработчиков Linux g++ будет необходимо для обеспечения эта функция также для них) (oops - это даже относится к STL)
  • возможность оставить это кодирование стиля C позади (игнорируя возвращаемые значения) и использовать отладчик с исполняемым кодом отладки, чтобы узнать, что не удается в нетривиальной среде с дочерними процессами и совместно используемыми библиотеками, предоставленными третьими лицами или удаленное выполнение
  • возможность возвращать богатую информацию об ошибках вызывающему абоненту без простого сброса всего на stderr

Ответ 7

Существует только одна возможность справиться с отказом в распределении по предположениям, изложенным в вопросе:

  • что распределитель принудительно завершает работу при выходе из строя. В частности, для этого требуется распределитель cusror.

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