Есть ли способ отловить исключение при создании статического / глобального? - PullRequest
0 голосов
/ 29 февраля 2012

Примите во внимание следующую ужасность:

#include <iostream>

struct thing
{
    thing()
    { 
        std::cout << "thing ctor\n";
        throw 5; 
    }
};

void SomeTerminateHandler()
{
    std::cout << "Uncaught exception!?\n";
}

int IHopeThisGetsCalledFirst()
{
    std::cout << "IHopeThisGetsCalledFirst()\n";
    std::set_terminate(SomeTerminateHandler);
    return 2;
}

const int x = IHopeThisGetsCalledFirst();
const thing y;

int main()
{
}

Вывод:

IHopeThisGetsCalledFirst()
thing ctor
Uncaught exception!?

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

abort вызывается после SomeTerminateHandler в вышеуказанной программе.Зачем? Это говорит: «Обработчик завершения по умолчанию вызывает функцию сброса cstdlib».- но я не использую обработчик завершения по умолчанию, и мой не вызывает abort.

Могу ли я что-нибудь сделать для обработки исключений во время статической инициализации.Если нет, то почему?Почему в языке нет чего-то, что позволяло бы это?

Ответы [ 3 ]

2 голосов
/ 29 февраля 2012

Что можно сделать в SomeTerminateHandler, чтобы «перехватить» исключение, чтобы я мог отобразить диалоговое окно с ошибкой или выйти из системы с подробным описанием ошибки?

Ничего - только обработчики исключений могут получить доступ к брошенному исключению.

abort вызывается после SomeTerminateHandler в вышеуказанной программе. Почему?

Ваш обработчик завершения не должен возвращаться; Стандарт (C ++ 11, 18.8.3.1) требует, чтобы он «завершил выполнение программы без возврата вызывающей стороне» - страница, на которую вы ссылаетесь, также говорит то же самое. Если вы нарушите это требование, тогда может произойти все, что угодно.

Что я могу сделать для обработки исключений во время статической инициализации?

Вы можете перехватить исключение в конструкторе; или вы можете избежать сложных статических объектов.

Если нет, то почему? Почему в языке нет чего-то, что позволяло бы это?

Я не могу ответить почему, но C ++ плохо обрабатывает сложные статические объекты. Даже если у вашего компилятора есть нестандартные расширения для указания порядка инициализации, я советую по возможности избегать их.

1 голос
/ 29 февраля 2012

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

C ++ не имеет четко определенных конструкций для пользовательских объектов, связанных внешне или созданных в области видимости файла. Как правило, это проблематично с такими проблемами, как неопределенный порядок инициализации. Без четкого определения того, что должно происходить в отношении таких вещей, как порядок инициализации, было бы трудно определить значимое поведение try / catch (куда можно поместить блок try / catch, например, если какой-либо объект, созданный в каком-либо модуле компиляции в система может скинуть?).

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

Если вам нужно быстрое решение, мы можем лениво конструировать вещи:

thing& my_thing()
{
    static thing obj;
    return obj;
}

Это гарантирует, что thing не будет создан до тех пор, пока эта функция не будет впервые вызвана, что означает, что он не будет создан вне вашей основной точки входа, если у вас нет другого глобального объекта, который вызывает это (прямо или косвенно) через его конструктор.

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

0 голосов
/ 29 февраля 2012

Могу ли я что-нибудь сделать для обработки исключений во время статической инициализации.Если нет, то почему бы и нет?

Нет, поскольку порядок инициализации не указан стандартом.

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

abort вызывается после SomeTerminateHandler в вышеуказанной программе.Зачем?Это говорит: «Обработчик завершения по умолчанию вызывает функцию сброса cstdlib».- но я не использую обработчик завершения по умолчанию, а мой не вызывает abort.

Скорее всего, ваш обработчик не инициализирован вовремя (исключение выдается до инициализации вашего обработчика).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...