我有一个类似的问题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
)与每个列表框条目相关联,以便以后可以访问它?
我意识到我可以获取列表框条目的文本,然后在地图中找到它并以此方式获取。但是,如果有更直接的方法将两者联系在一起吗?
答案 0 :(得分:4)
std::map
被指定为永远不会移动现有元素的关联容器,请参阅[associative.reqmts]/9:
insert
和emplace
成员不应影响迭代器和对容器的引用的有效性,erase
成员应仅使迭代器和对已擦除元素的引用无效。
在实践中,它通常被实现为红黑树。
因此,保持指向现有元素的指针是安全的,只要它们的生命周期超过指针的生命周期。
请注意,如果切换到std::unordered_map
(哈希映射),您将失去该保证。
设置:
m_lbPublishers.SetItemDataPtr(i, &mapPublisher.second);
要检索:
auto psEntry = (S_DEMO_ENTRY_EX*)m_lbPublishers.GetItemDataPtr(i);
CListBox::GetItemDataPtr()
会返回void*
,因此需要进行投射。
答案 1 :(得分:2)
只要不破坏/删除映射的节点,就可以将指向映射的数据类型的指针直接传递给CListBox::SetItemDataPtr
。
因此,在您的情况下访问S_DEMO_ENTRY_EX
并使用&mapPublisher.second
指针是正常的。
这由STL的规则保证