我有一个类型为<const char *, std::list<void *>>
的unordered_map,我有一个很大的值列表,我正在迭代以查看某些条件是否匹配。如果有匹配,我想在值的索引处将指向某个值的指针附加到std :: list。
const char *handler_name = NULL;
while (handler_name = all_handlers->get(), handler_name)
{
if (condition)
{
//Add pointer element to every event handler it registers
std::list<void *> scripts = responders[handler_name];
if (scripts.size() == 0)
{
responders[handler_name] = scripts;
}
scripts.push_back(static_cast<void *> (L));
active_states[static_cast<void *> (L)] = 1; //set to active so we only delete it once
}
handler_name = NULL;
}
这些是我的变量声明:
private:
std::unordered_map<const char*, std::list<void *>> responders;
std::unordered_map<void *, int> active_states;
all_handlers
是一个自定义列表类型,我正在迭代,如果非常规地获取所有const char * C字符串以用作潜在键,如果条件匹配。
然而,gdb揭示了一个std :: list永远不会被初始化为感兴趣的键,我认为这与我担心为handler_name的每个值初始化std :: list并同时需要它有关。在附加新值之前检查条目以查看列表是否已存在。
在这种情况下进行正确初始化的最佳方法是什么?
答案 0 :(得分:1)
假设您的condition
不是永远错误的表达,...
一旦条目添加到list
地图,您的responders
就会被初始化。那是C ++:你不能拥有'未初始化'列表。它们是完全构造的,或者它们不存在。 (在RAII上阅读)
此代码片段:
std::list<void *> scripts = responders[handler_name];
if (scripts.size() == 0)
{
responders[handler_name] = scripts;
}
是无操作。来自scripts
的{{1}}变量是复制(值语义!)。如果后者是空的,你只是把它复制回来......
可能你的意思是引用条目中的列表,并添加到:
responders[handler_name]
(注意:如果您想知道列表是否为空,请使用auto & scripts = responders[handler_name];
scripts.push_back(static_cast<void *> (L));
...更清楚!Express intent!)
答案 1 :(得分:0)
const char* handler_name = NULL;
while (handler_name = all_handlers->get(), handler_name)
这不是编写循环的惯用方法。事实上,它非常很奇怪。
考虑一种更传统的方法:
const char* handler_name = NULL;
while ((handler_name = all_handlers->get()))
(双括号是必要的,以防止某些编译器发出关于=
和==
之间可能混淆的警告。
或者改为使用for
:
for (const char* handler_name = all_handlers->get(); handler_name; handler_name = all_handlers->get())
我担心为handler_name的每个值初始化一个std :: list,
我不知道这意味着什么。表达式responders[handler_name]
将为该值初始化一个空的std::list
,如果地图中没有该值的话。但这就是你需要发生的事情。
这是胡说八道:
std::list<void *> scripts = responders[handler_name];
if (scripts.size() == 0)
{
responders[handler_name] = scripts;
}
scripts.push_back(static_cast<void *> (L));
首先评估responders[handler_name]
,它会返回与该键对应的std::list
(如果已经存在,则创建一个空的)。
然后将该列表复制到名为scripts
的新对象中。
然后,如果scripts
不为空,则通过复制scripts
(必须完全没有意义,因为{取代地图中的值 {1}} ia是地图中值的副本,因此如果scripts
不为空,则地图中的值不为空。)
然后最后修改列表的{em> copy ,scripts
,这是一个在循环结束时超出范围的局部变量,因此您永远不会添加任何条目存储在地图中的列表。
同时需要在添加新值之前检查条目以查看列表是否已存在。
你不需要这样做。 scripts
为你做到了。如果没有该密钥的条目,则会创建一个。
在这种情况下进行正确初始化的最佳方法是什么?
不要再为此烦恼,然后编写无意义的代码以避免出现问题。 responses[handler_name]
执行您需要的所有初始化。它会查找与该键对应的列表,如果未找到列表,则会正确初始化一个列表。
可以简单地写出一大堆废话:
responses[handler_name]
responses[handler_name].push_back(static_cast<void *> (L));
active_states[static_cast<void *> (L)] = 1; //set to active so we only delete it once
可能甚至不是必需的,因为任何指针都会隐式转换为static_cast<void*>
。如果你想更清楚地了解转换,你可以保留它们,但我只想写:
void*
这更短,更简单,并且不包含混乱的代码来解决不存在的问题。