将 std::map 项设置为 CListBox 的项数据

Setting std::map items as itemdata of CListBox

我有一个类似的问题但是这个新问题的上下文不同。

背景

我有这个变量: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) 中的每个条目与每个列表框条目相关联,以便我以后可以访问它?

我意识到我可以获取列表框条目的文本,然后在地图中找到它并以这种方式获取它。但是有没有更直接的方法把两者绑在一起呢?

只要映射的节点不是 destroyed/deleted,您就可以将指向映射数据类型的指针直接传递给 CListBox::SetItemDataPtr

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

这是由 STL 规则保证的

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

The insert and emplace members shall not affect the validity of iterators and references to the container, and the erase members shall invalidate only iterators and references to the erased elements.

在实践中,它通常实现为 red-black 树。

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

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


设置:

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

检索:

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

CListBox::GetItemDataPtr() returns void* 所以需要演员表。