【问题标题】:How do we use smart pointers with CFileDialog and multi-file selection?我们如何在 CFileDialog 和多文件选择中使用智能指针?
【发布时间】:2021-12-11 23:57:18
【问题描述】:

如何对使用通用CFileDialog 对话框的代码进行现代化改造?

示例代码:

void CExportSettingsDlg::OnBnClickedMfcbuttonImportXsl()
{
    CString strFilter;                                  // This will be used to display the right type of template files
    CString strTargetFolder = theApp.GetWorkingPath();  // Default
    TCHAR* pszFile = new TCHAR[32767];                  // Buffer for the files selected by the user
    TCHAR szTabText[_MAX_PATH] = { 0 };                 // Buffer for the selected tab text (we use it for the filter description)

    // Initialise the filter string
    strFilter = _T("Styles|SRRSchedule*.xsl;SRRSchedule*.css||");

    // Initialise the file dialog
    CFileDialog dlgImport(TRUE,
        _T(".XSL"), _T(""), OFN_ALLOWMULTISELECT | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, strFilter, this);
    ZeroMemory(pszFile, 32767 * sizeof(TCHAR));
    dlgImport.m_ofn.lpstrFile = pszFile;
    dlgImport.m_ofn.nMaxFile = 32767;
    dlgImport.m_ofn.nFileOffset = 0;

    if (dlgImport.DoModal() != IDOK)
    {
        // User did not select any files so tidy up the memory
        delete[] pszFile;
        return;
    }

    // Iterate the selected files
    POSITION pos = dlgImport.GetStartPosition();
    CString strSourceFilePath, strTargetFilePath, strSourceFileName, strSourceFileTitle, strSourceExtension, strFileName;

    while (pos)
    {
        strSourceFilePath = dlgImport.GetNextPathName(pos);
        // ...
    }

    // Tidy memory
    delete[] pszFile;
}

我们怎样才能把它变成使用智能指针? lpstrFile 变量的类型为 LPWSTR

【问题讨论】:

  • 在这种情况下,最简单的就是TCHAR* pszFile = new TCHAR[32767]; -> TCHAR pszFile[32767] = {0};
  • @Jabberwocky 我不知道它是否适用于这种情况,但有时在使用过多内存时会收到堆栈大小警告(不记得正确的术语)。我会让@Iinspectable 发表评论。
  • 是的,拥有大的局部变量(在大多数平台上存储在堆栈中)并不是一个好主意。但是 32767 并没有那么多。
  • @Jabberwocky 当你像你说的那样做时,你仍然会收到指针衰减警告。除非我改变dlgImport.m_ofn.lpstrFile = &pszFile[0];。然后就OK了。
  • @jab "32767 没那么多" - 这是 UNICODE 构建中的 64KiB。默认堆栈大小为 1MiB,占可用堆栈空间的 6.25%,仅针对此单个数组。这很多。 64 位构建的情况更糟,64 位调用约定加剧了这种情况,其中堆栈需要 16 字节对齐,加上 32 字节的影子空间(对于除叶函数之外的每个函数调用)。这对堆栈有很大的压力,如果可能的话,最好不要增加压力。这里可以。

标签: visual-c++ mfc smart-pointers openfiledialog


【解决方案1】:

当您需要一个自动管理的堆分配数组时,std::vector 是首选解决方案。所有new[]'s 和delete[]'s 将奇迹般地消失,并且OPENFILENAME 结构中设置的参数将匹配,作为奖励。

类似这样的:

void CExportSettingsDlg::OnBnClickedMfcbuttonImportXsl()
{
    // ...
    // The controlled sequence is default-initialized (i.e. zeroed out)
    auto pszFile = std::vector<TCHAR>(32767);

    // ...

    // Initialise the file dialog
    CFileDialog dlgImport(TRUE,
        _T(".XSL"), _T(""), OFN_ALLOWMULTISELECT | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, strFilter, this);
    dlgImport.m_ofn.lpstrFile = pszFile.data();
    // Without the cast this would raise a signed/unsigned mismatch warning
    // depending on the target architecture
    dlgImport.m_ofn.nMaxFile = static_cast<uint32_t>(pszFile.size());
    dlgImport.m_ofn.nFileOffset = 0;

    if (dlgImport.DoModal() != IDOK)
    {
        // User did not select any files so simply return
        // Memory is cleaned up by vector's d'tor
        return;
    }

    // ...

    // No need to clean up
}

【讨论】:

  • 一个简单的TCHAR pszFile[32767] = {0}; 在这里不够好吗?
  • @jab 如果您可以使用多达 64KiB 的 1MiB 堆栈空间,它会的。当你这样做的时候,很多诊断就会出现。
  • 堆栈使用是使用向量的一个参数,但 OTOH 很容易增加堆栈大小,所以一些更合理的大小,如 8Mib。
  • @jab 当然可以,但是你为什么要在这里做呢?这不是性能关键代码,并且在实践中采用堆分配的非平凡成本不会引起注意。避免使用标准容器似乎没有任何直接价值。
猜你喜欢
  • 2016-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多