Я начинающий программист на C++, поэтому я никогда не писал код на C++ для чего-то старше C++11. Я читал Скотта Мейерса «Эффективный С++, 2-е издание» (я знаю, что он старый, но я думаю, что в нем все еще есть некоторые важные моменты).
В книге, согласно «Пункту 7», new
может генерировать исключения, которые следует обрабатывать.
Может ли new
по-прежнему создавать исключения?
Должен ли я быть готов к исключениям, которые могут быть вызваны умным указателем или new
?
Вы все равно не должны использовать new
напрямую почти во всех случаях, частично именно потому, что трудно сделать его использование безопасным для исключений. В отличие от интеллектуальных указателей, это не гарантирует, что объекты new
ed уничтожаются, а память освобождается автоматически при возникновении исключения (вне самого выражения new
).
@user4581301 user4581301 вопрос был конкретно об использовании new; вы не знаете его дела. Бывают ситуации, когда интеллектуальные указатели не подходят/невозможны.
Херб Саттер и Скотт Мейерс также отметили, что ситуация нехватки памяти — это практически необратимая ситуация. И, что еще хуже, с современными операционными системами они могут перераспределять память и потенциально позволить программе запрашивать большой блок памяти, но когда программа попытается использовать его в какой-то момент, она выдаст ошибку, потому что память была недоступна. t В самом деле доступен.
Также обратите внимание, что готовность к возникновению исключений не означает, что вы должны ставить try
/catch
при каждом использовании new
. Вам нужно только перехватывать исключения, когда вашей программе имеет смысл восстановиться после сбоя. (Как упоминалось выше для std::bad_alloc
из new
, это часто нигде.) Однако вы должны убедиться, что код безопасен для исключений и не допускает утечки памяти или других ресурсов в случае возникновения исключения.
@InigoSelwood комментарий просто предназначен для ответа на последнюю строку вопроса. Если бы это была законченная мысль и ответ, я бы написал ответ. Хотя при втором чтении это не такой полезный комментарий, как я думал. Спрашивающий, похоже, не спрашивает о new
с умными указателями. Я должен был обратить больше внимания на или.
@Eljay Пожалуйста, дайте определение fault the program
. Насколько я понимаю, настольные ОС не перегружают память виртуальный, поэтому они всегда смогут выполнить свои обещания... в конце концов. Кроме того, std::bad_alloc
может возникнуть в результате превышения какой-либо квоты, хотя, вероятно, ее еще нельзя восстановить.
@blank, вам не нужно помечать все эти версии языка C++, поэтому я удалил их. Эти теги предназначены для случаев, когда вас интересует (или ограничивает) версия (или версии) конкретный.
@PaulSanders • Мое понимание — и опыт — состоит в том, что ОС для настольных ПК действительно выделяют виртуальную память и могут вызвать ошибку программы, если они не смогут предоставить обещанную память. Частично в этой ситуации можно обвинить программы, которые являются «плохими гражданами», потому что они чрезмерно запрашивают память кучи, что является обычной практикой. В совокупности память становится перегруженной, что обычно не является проблемой, пока в редкой ситуации (на практике) это не становится проблемой. Но это будет намного позже, чем new
, казалось бы, удалось.
@Eljay Кажется, это зависит от платформы (что я подозревал): superuser.com/questions/1194263/…. Должен сказать, я предпочитаю подход Windows.
... случайное уничтожение процесса A из-за того, что процесс B ведет себя неправильно, кажется немного произвольным.
Да, при распределении new
может вызвать исключение bad_alloc
.
То есть, если вы не передадите const std::nothrow_t&
в качестве второго параметра, где вам будет гарантировано возвращаемое значение nullptr
См. подробности здесь
Могут ли умные указатели генерировать исключение?
@ Пусто, да. Даже с умным указателем что-то может пойти не так и понадобится контекстная информация, недоступная конструктору создаваемого класса (например, конструктору нужно открыть файл, а он не может. Что тогда делать?) или вышеупомянутое bad_alloc
. Интеллектуальный указатель обеспечит правильную очистку выделения и самого интеллектуального указателя, но вам все равно придется иметь дело с выброшенным исключением так или иначе.
Общеизвестно, что new
с nothrow
по-прежнему будет генерировать исключение, если генерируется конструктор новых объектов, что делает его значительно менее полезным, чем ожидалось.
@FrançoisAndrieux Интересно, но, возможно, не совсем неожиданно. Добавление кода для обработки такого (потенциального) исключения значительно усложнит nothrow
new
и (что более важно) добавит накладные расходы.
При использовании интеллектуальных указателей избегайте использования
new
. Вместо этого используйте функцииmake_unique
иmake_shared
. Они выполняют нетривиальную очистку, если им не удастся создать экземпляр или что-то еще пойдет не так.