初始化std :: unordered_map的std :: list元素

时间:2016-07-27 06:12:33

标签: c++ list c++11 stl unordered-map

我有一个类型为<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并同时需要它有关。在附加新值之前检查条目以查看列表是否已存在。

在这种情况下进行正确初始化的最佳方法是什么?

2 个答案:

答案 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*

这更短,更简单,并且不包含混乱的代码来解决不存在的问题。