利用已有的bind构造ScopeExit
对于 ScopeExit,以前有提到过(见《这种代码结构如何组织?goto or do…while(0)?》http://www.zzzyk.com/kf/201205/132632.html)。使用场景再简单提一下:
bool GenFile()
{
HANDLE hFile = CreateFile(_T("Test.txt"), GENERIC_WRITE, 0, NUL, CREATE_ALWAYS, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return false;
}
CString strData = _T("test");
DWORD dwToWrite = strData.GetLength() * sizeof(TCHAR);
DWORD dwWritten = 0;
if (!WriteFile(hFile, (LPCTSTR)strData, dwToWrite, &dwWritten, NULL) || dwWritten != dwToWrite)
{
CloseHandle(hFile);
return false;
}
// if (...)
// {
// CloseHandle(hFile);
// return false;
// }
//
// ...
//
CloseHandle(hFile);
return true;
}
如上面这部分代码,如果 if … 之类的流程持续下去(如注释部分),每个 return false 之前都得带上 CloseHandle(),非常累赘。因此,出现了类似的 ScopeExit。boost 里有一个 BOOST_SCOPE_EXIT,Loki 里面也有一个 ScopeGuard。
继续使用刚才的案例,BOOST_SCOPE_EXIT 用法:
bool GenFile()
{
HANDLE hFile = CreateFile(_T("Test.txt"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return false;
}
BOOST_SCOPE_EXIT((hFile))
{
CloseHandle(hFile);
}
BOOST_SCOPE_EXIT_END
CString strData = _T("test");
DWORD dwToWrite = strData.GetLength() * sizeof(TCHAR);
DWORD dwWritten = 0;
if (!WriteFile(hFile, (LPCTSTR)strData, dwToWrite, &dwWritten, NULL) || dwWritten != dwToWrite)
{
return false;
}
// if (...)
// {
// return false;
// }
//
// ...
//
return true;
}
这样,每个 return 之前再也不必背负 CloseHandle 的包袱。
Loki::ScopeGuard 的用法:
bool GenFile()
{
HANDLE hFile = CreateFile(_T("Test.txt"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return false;
}
LOKI_ON_BLOCK_EXIT(CloseHandle, hFile);
CString strData = _T("test");
DWORD dwToWrite = strData.GetLength() * sizeof(TCHAR);
DWORD dwWritten = 0;
if (!WriteFile(hFile, (LPCTSTR)strData, dwToWrite, &dwWritten, NULL) || dwWritten != dwToWrite)
{
return false;
}
// if (...)
// {
// return false;
// }
//
// ...
//
return true;
}
从使用的简洁程度上看,Loki 更胜一筹。
另外,我们经常也遇到有条件的执行清理动作的情形,boost 和 Loki 都支持。先看 Loki 的使用案例:
bool GenFile()
{
LPCTSTR FILE_NAME = _T("Test.txt");
HANDLE hFile = CreateFile(FILE_NAME, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return false;
}
Loki::ScopeGuard sgDeleteFile = Loki::MakeGuard(DeleteFile, FILE_NAME);
LOKI_ON_BLOCK_EXIT(CloseHandle, hFile);
CString strData = _T("test");
DWORD dwToWrite = strData.GetLength() * sizeof(TCHAR);
DWORD dwWritten = 0;
if (!WriteFile(hFile, (LPCTSTR)strData, dwToWrite, &dwWritten, NULL) || dwWritten != dwToWrite)
{
return false;
}
// if (...)
// {
// return false;
// }
//
// ...
//
sgDeleteFile.Dismiss();
return true;
}
一开始,我们使用具名的 ScopeGuard,绑定了一个 DeleteFile(FILE_NAME) 的操作,到最后通过 Dismiss,让此操作不被执行。
相应地,boost 中,可以在进入 scope exit 之前设定一个变量,将此变量捕获入 scope exit,到最后给这个变量赋值,决定执不执行:
bool GenFile()
{
LPCTSTR FILE_NAME = _T("Test.txt");
HANDLE hFile = CreateFile(FILE_NAME, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return false;
}
bool bOK = false;
BOOST_SCOPE_EXIT((hFile)(&bOK))
{
if (!bOK)
{
CloseHandle(hFile);
}
}
BOOST_SCOPE_EXIT_END
CString strData = _T("test");
DWORD dwToWrite = strData.GetLength() * sizeof(TCHAR);
DWORD dwWritten = 0;
if (!WriteFile(hFile, (LPCTSTR)strData, dwToWrite, &dwWritten, NULL) || dwWritten != dwToWrite)
{
return false;
}
// if (...)
// {
// return false;
// }
//
// ...
//
bOK = true;
return true;
}
注意,此处捕获 bOK 的时候才用指针的形式,以保证最后对
补充:软件开发 , C++ ,