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

Setting std::map items as itemdata of CListBox

本文关键字:CListBox 数据 设置 map std      更新时间:2023-10-16

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

背景

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

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

std::map被指定为从不移动现有元素的关联容器,请参阅 [associaciative.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*因此需要强制转换。

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

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

这是由STL规则保证