Как поймать неуправляемое исключение С++ в управляемом С++
Я разрабатываю тонкую управляемую С++-оболочку над большой неуправляемой библиотекой С++ и большую библиотеку С#. Мне нужно ловить ошибки, возникающие из этой большой неуправляемой библиотеки С++, и реконструировать их как исключения Clr. Неуправляемая библиотека выдает экземпляры следующего класса:
Error::Error(const std::string& file, long line,
const std::string& function,
const std::string& message) {
message_ = boost::shared_ptr<std::string>(new std::string(
format(file, line, function, message)));
}
const char* Error::what() const throw () {
return message_->c_str();
}
До сих пор я придумал следующее:
try{
// invoke some unmanaged code
}
catch(Object*)
{
throw gcnew System::Exception("something bad happened");
}
Как извлечь сообщение из класса Error и преобразовать его в класс Clr String, чтобы я мог передать его в конструктор gcnew System:: Exception()?
Если неуправляемый код выбрасывает что-то еще, будет ли мой блок catch поймать его?
Изменить: я использую catch (Object *), потому что это рекомендуется в MCDN
Ответы
Ответ 1
Не работает ли для вас следующее?
try
{
// invoke some unmanaged code
}
catch (Error const& err)
{
throw gcnew System::Exception(gcnew System::String(err.what()));
}
Потому что это, безусловно, работает для меня:
#pragma managed(push, off)
#include <string>
struct Error
{
explicit Error(std::string const& message) : message_(message) { }
char const* what() const throw() { return message_.c_str(); }
private:
std::string message_;
};
void SomeFunc()
{
throw Error("message goes here");
}
#pragma managed(pop)
int main()
{
using namespace System;
try
{
try
{
SomeFunc();
}
catch (Error const& err)
{
throw gcnew Exception(gcnew String(err.what()));
}
}
catch (Exception^ ex)
{
Console::WriteLine(ex->ToString());
}
Console::ReadLine();
}
Ответ 2
Я использую
#include <exception>
#include <msclr\marshal.h>
using namespace System;
using namespace msclr::interop;
try
{
...
}
catch (const std::exception& e)
{
throw gcnew Exception(marshal_as<String^>(e.what()));
}
catch (...)
{
throw gcnew Exception("Unknown C++ exception");
}
Вы можете поместить это в пару макросов, так как они будут использоваться везде.
Вы можете добавить пользовательский catch
блок со своим классом Error
, но поскольку он, как представляется, происходит из std::exception
, код, который я вам показываю, должен быть в порядке.
Вы также можете захотеть поймать более конкретно std::invalid_argument
и перевести его на ArgumentException
и т.д., но я нахожу этот перебор.
Ответ 3
Единственный надежный способ, с помощью которого я смог поймать большинство неуправляемых исключений, - это улов (...), который не даст вам никакой информации для восстановления, но предотвратит большинство сбоев. Есть еще некоторые исключения, которые даже catch (...) не поймают и не будут разбивать ваше приложение, даже без индикатора сбоя (приложение просто исчезает), например, если плохо написанное стороннее приложение использует SetJump/LongJump с неправильным обработки ошибок или протоколов потоков.
Вы можете написать длинную серию блоков catch, если хотите попытаться ввести много исключений С++, например:
catch (int i)
{
// Rethrow managed with int data
}
catch (double d)
{
// Rethrow managed with double data
}
... etc
catch (...)
{
// Rethrow managed "I got a general exception" error
}