【问题标题】:Setting std::map items as itemdata of CListBox将 std::map 项设置为 CListBox 的 itemdata
【发布时间】:2018-03-28 08:05:06
【问题描述】:

我有一个类似的问题here,但这个新问题的背景不同。

背景

我有这个变量:PublisherMap m_mapPublishers;

PublisherMap的定义是:

using PublisherMap = std::map<CString, S_DEMO_ENTRY_EX>;

代码

我有这个方法可以读取地图并填充CListBox

bool CChristianLifeMinistryPersonalCopiesDlg::InitPublishersGrid()
{
    try
    {
        m_lbPublishers.ResetContent();

        for (auto & mapPublisher : m_mapPublishers)
        {
            bool bInclude = false;

            if (m_iDisplayMode == DISPLAY_EVERYONE)
                bInclude = true;
            else if (m_iDisplayMode == DISPLAY_BROTHER && mapPublisher.second.eGender == GENDER_MALE)
                bInclude = true;
            else if (m_iDisplayMode == DISPLAY_SISTER && mapPublisher.second.eGender == GENDER_FEMALE)
                bInclude = true;

            if (bInclude && m_bLimitDisplay)
            {
                CString strTemp;
                if (!m_mapSSAssignedPublishers.Lookup(mapPublisher.first, strTemp))
                    bInclude = FALSE;
            }

            if (bInclude)
            {
                int i = m_lbPublishers.AddString(mapPublisher.first);
                m_lbPublishers.SetItemData(i, MAKEWPARAM(mapPublisher.second.eGender, mapPublisher.second.eAppointed));

            }
        }
    }
    catch (_com_error e)
    {
        LPCTSTR szError = e.ErrorMessage();
        AfxMessageBox(szError);
        return false;
    }
    catch (CException* e)
    {
        e->Delete();
        AfxMessageBox(_T("CException"));
        return false;
    }

    m_iSelectMode = SELECT_NONE;
    UpdateData(FALSE);

    return true;
}

注意我使用了商品数据:

m_lbPublishers.SetItemData(i, 
    MAKEWPARAM(mapPublisher.second.eGender, mapPublisher.second.eAppointed));

它工作得很好。如果我使用CPtrArray,我会为列表框中的每个条目分配实际的结构对象指针。

问题

我不太了解std::map 的机制。是否有任何安全的方法可以将地图 (mapPublisher) 中的每个条目与每个列表框条目直接关联,以便我以后可以访问它?

我意识到我可以获取列表框条目的文本,然后在地图中找到它并以这种方式获取它。但如果有更直接的方式将两者联系起来呢?

【问题讨论】:

    标签: c++ mfc stdmap clistbox


    【解决方案1】:

    std::map 被指定为永远不会移动现有元素的关联容器,请参阅[associative.reqmts]/9

    insertemplace 成员不应影响迭代器和对容器的引用的有效性,erase 成员应仅使迭代器和对已擦除元素的引用无效。

    在实践中,它通常被实现为红黑树。

    因此,保留指向现有元素的指针是安全的,只要它们的生命周期超过指针的生命周期。

    请注意,如果您切换到 std::unordered_map(哈希映射),您将失去该保证。


    设置:

        m_lbPublishers.SetItemDataPtr(i, &mapPublisher.second);
    

    检索:

        auto psEntry = (S_DEMO_ENTRY_EX*)m_lbPublishers.GetItemDataPtr(i);
    

    CListBox::GetItemDataPtr() 返回void*,因此需要强制转换。

    【讨论】:

    • 这很难!我发现你的两个答案都很有用。你们都提供了将其合并为一个答案的信息。
    • 这是对答案的一个很好的增强。这也可能会添加到您的答案中,以获得更现代的演员阵容static_cast&lt;S_DEMO_ENTRY_EX*&gt;(m_lbPublishers.GetItemDataPtr(i));
    • CListBox::SetItemDataPtr 更适合这里。 SetItemData 需要演员表。两者都在项目数据中设置相同的字段,但前者采用指针类型,而后者采用DWORD_PTR
    • 糟糕,我就是这个意思。更新。 static_cast 与 C 风格的演员阵容完全是另一个讨论,我想留在那个 :-) 在这种情况下,任何一个都可以工作。
    【解决方案2】:

    只要映射的节点没有被破坏/删除,您就可以将指向映射数据类型的指针直接传递给CListBox::SetItemDataPtr

    因此,在您的情况下,访问 S_DEMO_ENTRY_EX 并使用 &amp;mapPublisher.second 的指针是可以的。

    STL 的规则保证了这一点

    【讨论】:

    • 谢谢。与此相关的是,将指针返回的更现代的方法是什么。目前我有:S_DEMO_ENTRY_EX *psEntry = (S_DEMO_ENTRY_EX*)m_lbPublishers.GetItemDataPtr(i);.
    • 我从不使用旧的 C 演员表。我会使用 static_cast(m_lbPublishers.GetItemDataPtr(i));但是为了更加类型安全,您可以为列表框派生自己的类并使用您自己的访问器函数,这些函数使用正确的类型。对于编译器来说,最后都是一样的。
    • 太棒了。我现在有一个问题,因为我已经提供了两个答案,它们都提供了不同的信息并且与答案有关。我想接受你的两个答案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-04
    • 2017-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多