是否可以将变量分配给函数中的变量一次?
Is it possible to assign a variable to a variable in my function only once?
就拿这个有点办法:
int CMeetingScheduleAssistantApp::DoMessageBox(LPCTSTR lpszPrompt, UINT nType, UINT nIDPrompt)
{
CString strContent = CString(lpszPrompt);
CString strTitle = CString();
if (!CTaskDialog::IsSupported())
return CWinAppEx::DoMessageBox(lpszPrompt, nType, nIDPrompt);
ENSURE(strTitle.LoadString(AFX_IDS_APP_TITLE));
CTaskDialog dlgTaskMessageBox(strContent, _T(""), strTitle);
// =================================
// Can this be calculated just once?
HDC screen = GetDC(nullptr);
auto hSize = static_cast<double>(GetDeviceCaps(screen, HORZSIZE));
auto hRes = static_cast<double>(GetDeviceCaps(screen, HORZRES));
auto PixelsPerMM = hRes / hSize; // pixels per millimeter
auto MaxPixelWidth = PixelsPerMM * 150.0;
auto PixelWidth = (hRes / 100.0) * 30.0;
// =================================
int iDialogUnitsWidth = MulDiv(
min(static_cast<int>(PixelWidth), static_cast<int>(MaxPixelWidth)), 4, LOWORD(GetDialogBaseUnits()));
dlgTaskMessageBox.SetDialogWidth(iDialogUnitsWidth);
// Code snipped
}
是否可以调整此函数,使其只计算一次 MaxPixelWidth
值?无需向我的 class?
添加其他变量
我的 objective 允许多次调用 DoMessageBox
并且只计算一次最大宽度。
这可以通过标记函数局部值 static
轻松完成。静态变量最多初始化一次。由于需要将变量初始化为执行代码的结果,因此需要 C++ 的另一个强大功能:立即计算 lambda expressions.
将 // =================================
注释之间的代码替换为以下内容即可完成所要求的内容。
static auto const MaxPixelWidth = []() {
HDC screen = GetDC(nullptr);
auto hSize = static_cast<double>(GetDeviceCaps(screen, HORZSIZE));
auto hRes = static_cast<double>(GetDeviceCaps(screen, HORZRES));
auto PixelsPerMM = hRes / hSize; // pixels per millimeter
ReleaseDC(screen);
return PixelsPerMM * 150.0;
}();
这确保 MaxPixelWidth
最多初始化一次,无法从函数外部访问,并且可以 const
以防止对其进行意外更改。
Live demo 来说明这个概念。
请记住几件事,以帮助您了解后果,并就是否要使用上述内容做出明智的决定:
使用局部函数静态变量不是免费的。如果您查看 Compiler Explorer 的反汇编,您会发现两个细节:
- 编译器分配一个隐藏标志,用于存储静态是否已初始化。
- 隐藏标志在锁下更新,以防止并发线程多次初始化静态。
在访问静态变量之前,编译器发出代码来检查初始化标志。 Clang 和 GCC 似乎都使用双重检查锁定来避免在每次访问时都锁定(具有不小的成本)。这种情况下的 space 和时间开销可以忽略不计。我也尝试理解 MSVC 的代码,但没有多大意义。访问静态 可能 总是锁定会更昂贵。
底线:使用所谓的魔法静态 并不是严格意义上的零成本抽象。您总是需要为标志和线程安全的实现付费,即使在您的用例中两者都不是严格要求的。
就拿这个有点办法:
int CMeetingScheduleAssistantApp::DoMessageBox(LPCTSTR lpszPrompt, UINT nType, UINT nIDPrompt)
{
CString strContent = CString(lpszPrompt);
CString strTitle = CString();
if (!CTaskDialog::IsSupported())
return CWinAppEx::DoMessageBox(lpszPrompt, nType, nIDPrompt);
ENSURE(strTitle.LoadString(AFX_IDS_APP_TITLE));
CTaskDialog dlgTaskMessageBox(strContent, _T(""), strTitle);
// =================================
// Can this be calculated just once?
HDC screen = GetDC(nullptr);
auto hSize = static_cast<double>(GetDeviceCaps(screen, HORZSIZE));
auto hRes = static_cast<double>(GetDeviceCaps(screen, HORZRES));
auto PixelsPerMM = hRes / hSize; // pixels per millimeter
auto MaxPixelWidth = PixelsPerMM * 150.0;
auto PixelWidth = (hRes / 100.0) * 30.0;
// =================================
int iDialogUnitsWidth = MulDiv(
min(static_cast<int>(PixelWidth), static_cast<int>(MaxPixelWidth)), 4, LOWORD(GetDialogBaseUnits()));
dlgTaskMessageBox.SetDialogWidth(iDialogUnitsWidth);
// Code snipped
}
是否可以调整此函数,使其只计算一次 MaxPixelWidth
值?无需向我的 class?
我的 objective 允许多次调用 DoMessageBox
并且只计算一次最大宽度。
这可以通过标记函数局部值 static
轻松完成。静态变量最多初始化一次。由于需要将变量初始化为执行代码的结果,因此需要 C++ 的另一个强大功能:立即计算 lambda expressions.
将 // =================================
注释之间的代码替换为以下内容即可完成所要求的内容。
static auto const MaxPixelWidth = []() {
HDC screen = GetDC(nullptr);
auto hSize = static_cast<double>(GetDeviceCaps(screen, HORZSIZE));
auto hRes = static_cast<double>(GetDeviceCaps(screen, HORZRES));
auto PixelsPerMM = hRes / hSize; // pixels per millimeter
ReleaseDC(screen);
return PixelsPerMM * 150.0;
}();
这确保 MaxPixelWidth
最多初始化一次,无法从函数外部访问,并且可以 const
以防止对其进行意外更改。
Live demo 来说明这个概念。
请记住几件事,以帮助您了解后果,并就是否要使用上述内容做出明智的决定:
使用局部函数静态变量不是免费的。如果您查看 Compiler Explorer 的反汇编,您会发现两个细节:
- 编译器分配一个隐藏标志,用于存储静态是否已初始化。
- 隐藏标志在锁下更新,以防止并发线程多次初始化静态。
在访问静态变量之前,编译器发出代码来检查初始化标志。 Clang 和 GCC 似乎都使用双重检查锁定来避免在每次访问时都锁定(具有不小的成本)。这种情况下的 space 和时间开销可以忽略不计。我也尝试理解 MSVC 的代码,但没有多大意义。访问静态 可能 总是锁定会更昂贵。
底线:使用所谓的魔法静态 并不是严格意义上的零成本抽象。您总是需要为标志和线程安全的实现付费,即使在您的用例中两者都不是严格要求的。