通过 C++ 高效使用 [] 运算符无序映射

发布于 2024-11-27 07:34:37 字数 740 浏览 2 评论 0原文

首先,有人可以澄清一下,在 C++ 中,使用 [] 运算符与 unordered_map 一起进行查找是否包装了对 find() 方法的调用,或者使用 [] 运算符比 find() 更快?

其次,在下面的代码中,我怀疑如果键尚未在 unordered_map 中,我将通过行 map[key] = value 执行第二次查找以替换当键不存在时使用 [] 运算符创建的默认值。

这是真的吗?如果是这样,有没有一种方法(也许通过使用指针或其他东西)让我在任何情况下都只能执行一次查找(也许通过存储放置值/从中读取值的地址)并且仍然实现相同的功能吗?显然,如果是这样的话,这将是一个有用的效率提高。

以下是修改后的代码摘录:

    int stored_val = map[key]; // first look up. Does this wrap ->find()??

    // return the corresponding value if we find the key in the map - ie != 0
    if (stored_val) return stored_val;

    // if not in map
    map[key] = value; 
       /* second (unnecessary?) look up here to find position for newly 
          added key entry */

   return value;

Firstly could someone clarify whether in C++ the use of the [] operator in conjunction with an unordered_map for lookups wraps a call to the find() method, or is using the [] operator quicker than find()?

Secondly, in the following piece of code I suspect in cases where the key is not already in the unordered_map I am performing a second look up by way of the line map[key] = value in order to replace the default value created there by using the [] operator when a key is not present.

Is that true, and if so is there a way (perhaps by use of pointers or something) that I might only perform one look up in any case (perhaps by storing the address of where to place a value/read a value from) and still achieve the same functionality? Obviously this would be a useful efficiency improvement if so.

Here is the modified code excerpt:

    int stored_val = map[key]; // first look up. Does this wrap ->find()??

    // return the corresponding value if we find the key in the map - ie != 0
    if (stored_val) return stored_val;

    // if not in map
    map[key] = value; 
       /* second (unnecessary?) look up here to find position for newly 
          added key entry */

   return value;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

隐诗 2024-12-04 07:34:37

operator[] 将插入一个条目为您提供一个默认构造的值(如果尚不存在)。它相当于,但可能会比以下更有效地实现:

iterator iter = map.find(key);

if(iter == map.end())
{
    iter = map.insert(value_type(key, int())).first;
}

return *iter;

operator[] 比使用 find()insert(),因为它可以节省重新散列密钥。

解决代码中多次查找的一种方法是引用该值:

int &stored_val = map[key];

// return the corresponding value if we find the key in the map - ie != 0
if (stored_val) return stored_val;

// if not in map
stored_val = value;

return value;

请注意,如果映射中不存在该值,operator[] 将默认构造并插入一。因此,虽然这将避免多次查找,但如果与默认构造+分配比复制或移动构造慢的类型一起使用,它实际上可能会更慢。

不过,使用 int 时,它会廉价地默认构造为 0,您也许可以将 0 视为表示空的幻数。您的示例中可能就是这种情况。

如果你没有这样的神奇数字,你有两个选择。您应该使用什么取决于您计算该值的成本。

首先,当散列键成本较低但计算值成本较高时,find() 可能是最佳选择。这将散列两次,但仅在需要时计算值:

iterator iter = map.find(key);

// return the corresponding value if we find the key in the map
if(iter != map.end()) return *iter;

// if not in map
map.insert(value_type(key, value));

return value;

但是如果您已经获得了值,则可以非常有效地完成它 - 也许比上面使用引用 + 幻数更有效:

pair<iterator,bool> iter = map.insert(value_type(key, value));
return *iter.first;

如果 < 返回的 bool code>map.insert(value_type) 为 true,则项目已插入。否则,它已经存在并且没有进行任何修改。迭代器返回指向映射中插入或现有值的点。对于您的简单示例,这可能是最佳选择。

operator[] will insert an entry for you with a default-constructed value, if one isn't already there. It is equivalent to, but will probably be implemented more efficiently than:

iterator iter = map.find(key);

if(iter == map.end())
{
    iter = map.insert(value_type(key, int())).first;
}

return *iter;

operator[] can be quicker than doing the work manually with find() and insert(), because it can save having to re-hash the key.

One way you can work around having multiple lookups in your code is to take a reference to the value:

int &stored_val = map[key];

// return the corresponding value if we find the key in the map - ie != 0
if (stored_val) return stored_val;

// if not in map
stored_val = value;

return value;

Note that if the value doesn't exist in the map, operator[] will default-construct and insert one. So while this will avoid multiple lookups, it might actually be slower if used with a type that is slower to default-construct + assign than to copy- or move-construct.

With int though, which cheaply default-constructs to 0, you might be able to treat 0 as a magic number meaning empty. This looks like it might be the case in your example.

If you have no such magic number, you've got two options. What you should use depends on how expensive it is for you to compute the value.

First, when hashing the key is cheap but computing the value is expensive, find() may be the best option. This will hash twice but only compute the value when needed:

iterator iter = map.find(key);

// return the corresponding value if we find the key in the map
if(iter != map.end()) return *iter;

// if not in map
map.insert(value_type(key, value));

return value;

But if you've got the value already, you can do it very efficiently -- perhaps slighty more efficiently than using a reference + magic number as above:

pair<iterator,bool> iter = map.insert(value_type(key, value));
return *iter.first;

If the bool returned by map.insert(value_type) is true, the item was inserted. Otherwise, it already existed and no modifications were made. The iterator returned points to the inserted or existing value in the map. For your simple example, this may be the best option.

傲世九天 2024-12-04 07:34:37

您可以使用返回 pair的特殊 insert 函数检查元素是否存在,插入一个新元素(如果不存在) ; 其中布尔值告诉您该值是否已实际插入。例如,代码此处

  unordered_map<char, int> mymap;
  pair<unordered_map<char,int>::iterator,bool> ret;

  // first insert function version (single parameter):;
  mymap.insert ( pair<char,int>('z',200) );
  ret=mymap.insert (pair<char,int>('z',500) ); 
  if (ret.second==false)
  {
    cout << "element 'z' already existed";
    cout << " with a value of " << ret.first->second << endl;
  }

此处的代码插入对<'z' ,200> 进入地图(如果地图不存在)。如果返回的对的第二个元素的值为 true,则它返回插入的迭代器;或者,如果返回的对的第二个元素为 false,则返回该元素实际所在的迭代器。

You can both check if an element exists, and insert a new element if it does not exist, with the special insert function that returns a pair<iterator, bool> in which the boolean value tells you if the value has been actually inserted. For example, the code here:

  unordered_map<char, int> mymap;
  pair<unordered_map<char,int>::iterator,bool> ret;

  // first insert function version (single parameter):;
  mymap.insert ( pair<char,int>('z',200) );
  ret=mymap.insert (pair<char,int>('z',500) ); 
  if (ret.second==false)
  {
    cout << "element 'z' already existed";
    cout << " with a value of " << ret.first->second << endl;
  }

The code here inserts the pair <'z',200> into the map if it does not exist. It returns the iterator where it is inserted if the value of the second element of the pair returned is true, or, it returns the iterator where the element actually was, if the second element of the pair is false.

樱花细雨 2024-12-04 07:34:37

首先有人可以澄清一下,在 C++ 中,使用 [] 运算符与 unordered_map 一起进行查找是否包装了对 Find() 方法的调用,或者使用 [] 运算符比 Find() 更快?

对此没有任何规则。 [] 的实现可以使用 find(),它可以自行执行查找,也可以将查找委托给 也使用的某个私有方法find() 内部。

也无法保证哪一个更快。 find() 涉及构造和返回迭代器的开销,而如果键不存在,[] 可能会更慢,因为在这种情况下它会插入一个新值。

(...)有没有一种方法(也许通过使用指针或其他东西)让我在任何情况下都只能执行一次查找(...)

如果键不在地图中,[] 将插入一个新的默认构造值,并返回引用。因此,您可以存储该引用以保存第二次查找:

int& stored_val = map[key];  // Note the reference

if (stored_val) return stored_val;

// Use the reference to save a second lookup.
stored_val = value; 

return value;

Firstly could someone clarify whether in C++ the use of the [] operator in conjunction with an unordered_map for lookups wraps a call to the Find() method, or is using the [] operator quicker than Find()?

There is no rule for that. An implementation of [] could use find(), it could perform the lookup by itself or it could delegate the lookup to some private method that is also used by find() internally.

There is also no guarantee on which one is faster. find() involves an overhead in constructing and returning an iterator, whereas [] will probably be slower if the key does not exist, as it inserts a new value in this case.

(...) is there a way (perhaps by use of pointers or something) that I might only perform one look up in any case (...)

If the key is not in the map, [] will insert a new default-constructed value, and return a reference. Therefore, you could store that reference to save the second lookup:

int& stored_val = map[key];  // Note the reference

if (stored_val) return stored_val;

// Use the reference to save a second lookup.
stored_val = value; 

return value;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文