C++异常处理

C++异常处理

一.关键Api介绍

1.HRESULT

H result,错误代码id;

2.FormatMessage

格式化消息字符串;

DWORD FormatMessage(
  DWORD   dwFlags,					//格式化选项
  LPCVOID lpSource,					//消息定义的位置
  DWORD   dwMessageId,				//消息标识符HRESULT
  DWORD   dwLanguageId,				//语言标识符
  LPTSTR  lpBuffer,					//指向缓冲区的指针,这个是接受格式化后的字符串
  DWORD   nSize,
  va_list *Arguments
);

前面几个都有点用,最后两个好像没啥用;具体看MSDN官方文档

这个Api将错误id转化为了可读的字符串;

3.exception

windows系统runtime中的自带了exception类;

除了构造,拷贝构造,同类赋值,析构四套件外,还有一个公有的what方法和私有字段_Data结构体;

以下是__std_exception_data结构体;What是异常常量字符串;DoFree字面意思是否释放该内存;

image-20211004171921787

what方法中,判断data中的what字符串为空,返回未知异常,否则返回what;

image-20211004172114075

二.封装exception

最终目的是为了把异常打印出来,需要知道异常的具体位置,异常种类或消息;

GetOriginString :按格式打印错误种类;

其他都是简单代码;

//.h
class ChiliException : public std::exception
{
public:
	ChiliException( int line,const char* file ) noexcept;
	const char* what() const noexcept override;
	virtual const char* GetType() const noexcept;
	int GetLine() const noexcept;
	const std::string& GetFile() const noexcept;
	std::string GetOriginString() const noexcept;
private:
	int line;
	std::string file;
protected:
	mutable std::string whatBuffer;
};
//Cpp
ChiliException::ChiliException( int line,const char* file ) noexcept
	:
	line( line ),
	file( file )
{}

const char* ChiliException::what() const noexcept
{
	std::ostringstream oss;
	oss << GetType() << std::endl
		<< GetOriginString();
	whatBuffer = oss.str();
	return whatBuffer.c_str();
}

const char* ChiliException::GetType() const noexcept
{
	return "Chili Exception";
}

int ChiliException::GetLine() const noexcept
{
	return line;
}

const std::string& ChiliException::GetFile() const noexcept
{
	return file;
}

std::string ChiliException::GetOriginString() const noexcept
{
	std::ostringstream oss;
	oss << "[File] " << file << std::endl
		<< "[Line] " << line;
	return oss.str();
}

三.封装HRESULT异常类

在window类中添加一下两个异常类,对HRESULT格式化,将错误代码转成可读字符串返回出来;

//.h
class Exception : public ChiliException
{
	using ChiliException::ChiliException;
public:
	static std::string TranslateErrorCode(HRESULT hr) noexcept;
};

class HrException : public Exception
{
public:
	HrException(int line, const char* file, HRESULT hr) noexcept;
	const char* what() const noexcept override;
	const char* GetType() const noexcept override;
	HRESULT GetErrorCode() const noexcept;
	std::string GetErrorDescription() const noexcept;
private:
	HRESULT hr;
};

为了方便调用添加了两个宏定义,在需要抛出异常时,只需要写宏定义即可:

#define CHWND_EXCEPT( hr ) Window::HrException( __LINE__,__FILE__,(hr) )
#define CHWND_LAST_EXCEPT() Window::HrException( __LINE__,__FILE__,GetLastError() )

GetLastError :Win32Api,获取最后一个错误id,用来监控程序崩溃的异常;

//.cpp
std::string Window::Exception::TranslateErrorCode(HRESULT hr) noexcept
{
	char* pMsgBuf = nullptr;
	// windows will allocate memory for err string and make our pointer point to it
	//格式化消息字符串
	const DWORD nMsgLen = FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
		nullptr, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		reinterpret_cast<LPSTR>(&pMsgBuf), 0, nullptr
	);
	// 0 string length returned indicates a failure
	if (nMsgLen == 0)
	{
		return "Unidentified error code";
	}
	// copy error string from windows-allocated buffer to std::string
	std::string errorString = pMsgBuf;
	// free windows buffer
	LocalFree(pMsgBuf);
	return errorString;
}

Window::HrException::HrException(int line, const char* file, HRESULT hr) noexcept
	:
	Exception(line, file),
	hr(hr)
{}

const char* Window::HrException::what() const noexcept
{
	std::ostringstream oss;
	oss << GetType() << std::endl
		<< "[Error Code] 0x" << std::hex << std::uppercase << GetErrorCode()
		<< std::dec << " (" << (unsigned long)GetErrorCode() << ")" << std::endl
		<< "[Description] " << GetErrorDescription() << std::endl
		<< GetOriginString();
	whatBuffer = oss.str();
	return whatBuffer.c_str();
}

const char* Window::HrException::GetType() const noexcept
{
	return "Chili Window Exception";
}

HRESULT Window::HrException::GetErrorCode() const noexcept
{
	return hr;
}

std::string Window::HrException::GetErrorDescription() const noexcept
{
	return Exception::TranslateErrorCode(hr);
}

四.捕获异常

在WinMain中添加以下代码,捕获三种异常(系统异常,运行时,未知);

MessageBox是Win32Api,弹出错误框;

try{
//程序运行代码
}
catch (const ChiliException& e)
{
	MessageBox(nullptr, e.what(), e.GetType(), MB_OK | MB_ICONEXCLAMATION);
}
catch (const std::exception& e)
{
	MessageBox(nullptr, e.what(), "Standard Exception", MB_OK | MB_ICONEXCLAMATION);
}
catch (...)
{
	MessageBox(nullptr, "No details available", "Unknown Exception", MB_OK | MB_ICONEXCLAMATION);
}

测试代码:

	//test报错机制
	//throw CHWND_EXCEPT( ERROR_ABIOS_ERROR);
	//throw std::runtime_error("xxxxxxx");
	//throw "x";

效果:

image-20211004175503778image-20211004175532728image-20211004175610053

另外,通过修改一些参数再次测试正常报错机制(修改了创建窗口的类名);

image-20211004175712012

posted @ 2021-10-04 18:03  小紫苏  阅读(256)  评论(0编辑  收藏  举报