Почему создание static const std::string вызывает исключение?
У меня есть строковые константы, для строк, которые я использую в нескольких местах в своем приложении:
namespace Common{
static const std::string mystring = "IamAwesum";
}
Когда вы отправляете вопрос о чем-то еще (Что происходит с файлом .h, который не включен в цель во время компиляции?), другой пользователь сделал следующий комментарий
помните, что ваша статическая строка в этом случае является глобальной. Таким образом, они может создать исключение в любое время и не может быть уловом. Я советую тебе для использования функции, которая возвращает ссылку вашей строки. std::stringconst & mystring {static std::string const mystring = "IamAwesum"; return mystring} таким образом, ваш объект строится только при необходимости
Может кто-нибудь объяснить, почему использование статических константных строк таким образом, что я делаю это выше, рискует выбросить исключения?
Ответы
Ответ 1
N4140 § 3.6.2 [basic.start.init]/4
Определяется реализацией, является ли динамическая инициализация нелокальная переменная со статической продолжительностью хранения выполняется до первый оператор main
.
N4140 § N4140 15.3 [кроме ручки]/13
Исключения, брошенные в деструкторы объектов со статическим хранилищем длительность или в конструкторах объектов пространства имен со статическими длительность хранения не улавливается функцией-try-block на main()
.
Вы просто не можете поймать исключение, сгенерированное конструктором строк - скажем, std::bad_alloc
.
(мнение) Если сказать, что для таких маленьких строк я считаю такое рассмотрение параноидальным.
Ответ 2
PDF-документ в основном относится к исключениям из фиаско объекта ctor и инициализации с помощью статических или динамически связанных библиотек.
Единственная опасность, которую я вижу в вашем коде для исключений, - это то, что ctor std::string будет бросать, когда он вызывается.
Если вы действительно хотите быть в безопасности, вместо этого вы можете использовать статический const char * mystring, который не будет вызывать С++ ctor.
Также существует вопрос о том, что код находится в общей библиотеке, которая затем должна быть помещена в адресное пространство процесса.
Я не вижу в этом серьезной проблемы, если вы не используете сложные ctors (ctors, которые могут бросать).
Ответ 3
Единственная "проблема" - если вы можете назвать ее так, что я вижу с вашим кодом, так это то, что вы расточительны, ненужно копируя данные, которые уже являются константами в динамически распределенный буфер (который формально постоянный, но не в действительности). Это использует в два раза больше физической памяти по мере необходимости и делает ненужную копию.
Это имеет значение? Почти наверняка нет. Даже в системе с довольно ограниченной памятью это в настоящее время вряд ли будет заметным ни с точки зрения времени выполнения, ни из-за потребления памяти.
Что касается исключений, то, конечно, технически верно, что выделение, которое std::string
должно выполнить, может потерпеть неудачу, и, следовательно, конструктор может выбросить, и вы не сможете его поймать. Но, пожалуйста, будьте реалистами.
Это почти гарантировано не произойдет, но даже если это произойдет... если что-то столь же тривиальное, как выделение памяти для пары строк, сбой при запуске вашей программы, у вас действительно действительно серьезная проблема в совершенно другом масштабе! < ш > Кроме того, как указано в комментарии к другому ответу выше: Предполагая, что это произойдет, что вы собираетесь с этим делать? Программа полностью не может работать, поэтому не так много, чтобы убить программу, которую вы могли бы сделать.
Теперь, когда С++ 17 не находится далеко и string_view
уже доступен в std::experimental
для нескольких компиляторов mainstream, вы можете попробовать другое: используйте правильную вещь.
A string_view
будет, вопреки a string
, не выделять непостоянную память, скопировать в нее постоянные данные, а затем сделать вид константы. Вместо этого он будет управлять указателем непосредственно с постоянными данными, и все.
Таким образом, ваши константы действительно (не только формально) постоянны, нет никаких распределений, нет возможности исключений и нет использования двойной памяти. И по большей части он по-прежнему выглядит и пахнет как string
. Единственными заметными отличиями являются то, что a string_view
не гарантирует nul-term (но постоянная символа, на которую указывает, делает это неактуальной), и тот факт, что он действительно постоянный, не изменяемый... что именно вы хотите.