避免在unordered_map插入中执行额外的过程

时间:2013-02-11 22:55:50

标签: c++ memory-management reference unordered-map

我有std::unordered_map,我希望两者都增加std::pair中的第一个值,key哈希值,并创建对key的引用。例如:

std::unordered_map<int, std::pair<int, int> > hash;
hash[key].first++;

auto it(hash.find(key));
int& my_ref(it->first);

我可以,而不是使用[]运算符,使用insert()插入数据,但我会分配一对,即使它稍后要被解除分配,也会hash可能已经key - 不确定。更清楚:

// If "key" is already inserted, the pair(s) will be allocated
// and then deallocated, right?
auto it(hash.insert(std::make_pair(key, std::make_pair(0, 0))));
it->second.first++;

// Here I can have my reference, with extra memory operations,
// but without an extra search in `hash`
int& my_ref(it->first);

我非常倾向于使用第一种选择,但我似乎无法确定哪一种是最好的。有没有更好的解决方案?

P.S。:对我来说理想的解决方案就像插入一样,不需要初始的,可能无用的值分配。

3 个答案:

答案 0 :(得分:4)

正如其他人所指出的,“分配”std::pair<int,int>实际上只不过是复制两个整数(在堆栈上)。对于map<int,pair<int,int>>::value_typepair<int const, pair<int, int>>您处于三int s,因此使用第二种方法不会产生显着的开销。您可以使用emplace代替insert,即:

进行略微优化
// Here an `int` and a struct containing two `int`s are passed as arguments (by value)
auto it(hash.emplace(key, std::make_pair(0, 0)).first);
it->second.first++;

// You get your reference, without an extra search in `hash`
// Not sure what "extra memory operations" you worry about
int const& my_ref(it->first); 

使用hash[key]hash.find(key)的第一种方法必然会更昂贵,因为元素搜索肯定比迭代器解除引用更昂贵。

当所有参数都只是unordered_map<...>::value_type时,在构建int的过程中过早复制参数是一个可以忽略不计的问题。但是,如果您将重量级key_typepair重量级类型设为mapped_type,则可以使用上述的以下变体尽可能通过引用转发所有内容(并使用)为rvalues移动语义):

// Here key and arguments to construct mapped_type 
// are forwarded as tuples of universal references
// There is no copying of key or value nor construction of a pair 
// unless a new map element is needed.
auto it(hash.emplace(std::piecewise_construct, 
                        std::forward_as_tuple(key), // one-element tuple
                        std::forward_as_tuple(0, 0) // args to construct mapped_type
                     ).first);
it->second.first++;

// As in all solutions, get your reference from the iterator we already have
int const& my_ref(it->first); 

答案 1 :(得分:1)

这个怎么样:

auto it = hash.find(key);

if (it == hash.end()) { it = hash.emplace(key, std::make_pair(0, 0)).first; }

++it->second.first;

int const & my_ref = it->first;   // must be const

(如果是有序地图,您可以使用lower_bound并提示插入以回收树木漫步。)

答案 2 :(得分:1)

如果我理解正确,你想要的是operator[],它会返回iterator,而不是mapped_typeunordered_map的当前接口不提供此类功能,operator[]实现依赖于私有成员(至少是boost实现,我在我的环境中没有访问C ++ 11 std文件)。

我认为JoergB的答案会更快,而Kerrek SB的答案会更短。由您来决定对您的项目更重要的是什么。