微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

是否可以只将变量分配给我函数中的变量一次?

如何解决是否可以只将变量分配给我函数中的变量一次?

采取这种方法

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 举报,一经查实,本站将立刻删除。