如何解决是否可以只将变量分配给我函数中的变量一次?
采取这种方法:
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
值?不需要在我的类中添加其他变量?
我的目标是允许多次调用 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 来说明这个概念。
请记住以下几点,以帮助您了解后果,并就是否要使用上述内容做出明智的决定:
使用函数局部静态变量不是免费的。如果您查看编译器资源管理器的反汇编,您会发现两个细节:
- 编译器分配一个隐藏标志,用于存储静态是否已初始化。
- 隐藏标志在锁下更新,以防止并发线程多次初始化静态。
在访问静态变量之前,编译器会发出代码来检查初始化标志。 Clang 和 GCC 似乎都使用双重检查锁定来避免在每次访问时使用锁定(具有非平凡的成本)。这种情况下的空间和时间开销可以忽略不计。我也尝试理解 MSVC 的代码,但没有多大意义。始终使用锁来访问静态可能成本更高。
底线:使用所谓的魔法静态并不是严格意义上的零成本抽象。您总是为标志和线程安全实现付费,即使在您的用例中两者都不是严格要求的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。