Действительно ли “Законно” для времени выполнения C++ назвать оконечным (), когда код C++ используется в некоторой программе неC++?

В определенных случаях - особенно, когда исключение выходит из деструктора во время раскручивания стека - вызовы времени выполнения C++ terminate() который должен сделать что-то разумное вскрытие и затем выйти из программы. Когда вопрос, "почему так резкий" возникает ответ, обычно "нет ничего более разумного, чтобы сделать в таких ошибочных ситуациях". Это звучит разумным, если целая программа находится в C++.

Теперь, что, если код C++ находится в библиотеке и программе, которая пользуется библиотекой, не находится в C++? Это происходит довольно часто - например, у меня мог бы быть собственный COM-компонент C++, использованный программой.NET. Однажды terminate() назван в коде компонента, который программа.NET внезапно заканчивает неправильно. Автор программы будет, в первую очередь, думать, что "Я не забочусь о C++, какого черта эта библиотека, заставляют мою программу выйти?"

Как я обрабатываю последний сценарий при разработке библиотек в C++? Действительно ли это разумно это terminate() неожиданно заканчивает программу? Существует ли лучший способ обработать такие ситуации?

7
задан sharptooth 24 March 2010 в 12:47
поделиться

4 ответа

Почему среда выполнения C ++ вызывает terminate () ? Он не делает это случайно или из-за обстоятельств, которые нельзя определить и / или избежать при написании кода. Это происходит потому, что ваш код делает что-то, что определено для вызова terminate () , например, генерирует исключение из деструктора во время раскрутки стека.

В стандарте C ++ есть список всех ситуаций, которые определены как результат вызова terminate () . Если вы не хотите, чтобы вызывалась terminate () , не делайте ничего из этого в своем коде. То же самое относится к неожиданным () , abort () и т. Д.

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

Возможно, у вас есть конкретный пример, в котором трудно избежать вызова terminate () , но выброс исключения из деструктора во время раскрутки стека не так. Только никогда не выбрасывайте исключения из деструкторов. Это означает разработку деструкторов таким образом, чтобы, если они делают что-то, что может привести к сбою, деструктор перехватывает исключение, и ваш код продолжает работу в определенном состоянии.

Бывают ситуации, когда ваша система невежливо взломает ваш процесс из-за чего-то, что делает ваш код C ++ (хотя и не путем вызова terminate () ).Например, если система чрезмерно выделяет память и VMM не может выполнить обещания malloc / new , то ваш процесс может быть остановлен. Но это системная функция и, вероятно, в равной степени применима к другому языку, вызывающему ваш C ++. Я не думаю, что вы можете (или должны) что-то с этим сделать, если вызывающий абонент знает, что ваша библиотека может выделить память. В этом случае процесс завершился не по вине вашего кода, а с определенной реакцией операционной системы на нехватку памяти.

11
ответ дан 6 December 2019 в 10:49
поделиться

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

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

6
ответ дан 6 December 2019 в 10:49
поделиться

Предположим, у вас есть функция на C ++ с именем cppfunc и вы вызываете его из другого языка (например, C или .NET). Я предлагаю вам создать функцию-оболочку, скажем exportedfunc , например так:

int exportedfunc(resultype* outresult, paramtype1 param1, /* ... */)
{
    try {
       *outresult = cppfunc(param1,param2,/* ... */);
       return 0; // indicate success
    }catch( ... ) {  // may want to have other handlers
       /* possibly set other error status info */
       return -1; // indicate failure
    }
}   

По сути, вам нужно убедиться, что исключения не пересекают языковые границы ... поэтому вам нужно обернуть свои функции C ++ функция, которая перехватывает все исключения и сообщает код состояния или делает что-то приемлемое, кроме вызова std :: terminate.

1
ответ дан 6 December 2019 в 10:49
поделиться

Обработчик завершения по умолчанию вызовет abort . Если вам не нужно такое поведение, определите свой собственный обработчик завершения и установите его с помощью set_terminate .

0
ответ дан 6 December 2019 в 10:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: