4

我有一个std::unordered_map,并且我想要增加 a 中的第一个值,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);

我非常倾向于使用第一个选项,但我似乎无法决定哪个是最好的。有什么更好的解决方案吗?

PS:对我来说,一个理想的解决方案是像插入一样不需要初始的,可能是无用的,分配价值。

4

3 回答 3

4

正如其他人指出的那样,“分配” astd::pair<int,int>实际上只不过是复制两个整数(在堆栈上)。对于map<int,pair<int,int>>::value_type,即pair<int const, pair<int, int>>您处于 3int秒,因此使用第二种方法没有显着的开销。您可以通过使用emplace而不是insertie 稍微优化:

// 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当所有参数都只是ints时,在构造 的过程中过早复制参数是一个可以忽略不计的问题。但是,如果您有一个重量级key_typepair重量级类型作为mapped_type,您可以使用上面的以下变体尽可能通过引用转发所有内容(并对右值使用移动语义):

// 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); 
于 2013-02-15T22:23:41.847 回答
1

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

我想 JoergB 的答案会更快,而 Kerrek SB 的答案会更小。由您决定什么对您的项目更重要。

于 2013-02-19T16:47:39.950 回答
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并暗示插入来回收树行走。)

于 2013-02-11T23:02:04.237 回答