天天看點

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字面意思是否釋放該記憶體;

C++異常處理

what方法中,判斷data中的what字元串為空,傳回未知異常,否則傳回what;

C++異常處理

二.封裝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";
           

效果: