C++ c++;将find()映射到insert():如何优化操作?

C++ c++;将find()映射到insert():如何优化操作?,c++,stl,map,C++,Stl,Map,我正在使用STL映射数据结构,此时我的代码首先调用find():如果键以前不在映射中,它将调用insert()它,否则它什么也不做 map<Foo*, string>::iterator it; it = my_map.find(foo_obj); // 1st lookup if(it == my_map.end()){ my_map[foo_obj] = "some value"; // 2nd lookup }else{ // ok do nothing. }

我正在使用STL映射数据结构,此时我的代码首先调用find():如果键以前不在映射中,它将调用insert()它,否则它什么也不做

map<Foo*, string>::iterator it;
it = my_map.find(foo_obj);   // 1st lookup

if(it == my_map.end()){
  my_map[foo_obj] = "some value";  // 2nd lookup
}else{
  // ok do nothing.
}
map::迭代器;
it=my_map.find(foo_obj);//第一次查找
if(it==my_map.end()){
my_map[foo_obj]=“一些值”//第二次查找
}否则{
//好的,什么都不要做。
}
我想知道是否有比这更好的方法,因为据我所知,在这种情况下,当我想插入一个尚未出现的键时,我会在地图数据结构中执行两次查找:一次用于find(),一次在insert()(对应于操作符[])


提前感谢您的建议。

通常,如果您进行了查找,也可能是插入,那么您希望保留(并检索)旧值(如果它已经存在)。如果您只想覆盖任何旧值,
map[foo_obj]=“some value”
会这样做

以下是通过一次地图查找获取旧值或插入新值(如果不存在)的方法:

typedef std::map<Foo*,std::string> M;
typedef M::iterator I;
std::pair<I,bool> const& r=my_map.insert(M::value_type(foo_obj,"some value"));
if (r.second) { 
    // value was inserted; now my_map[foo_obj]="some value"
} else {
    // value wasn't inserted because my_map[foo_obj] already existed.
    // note: the old value is available through r.first->second
    // and may not be "some value"
}
// in any case, r.first->second holds the current value of my_map[foo_obj]

如果映射的类型不是默认可构造的,那么让F提供一个默认值,或者添加另一个参数来获取\u else\u compute。

有两种主要方法。第一种方法是使用insert函数,该函数采用值类型,并返回一个迭代器和一个bool,指示是否发生了插入,并向具有相同键的现有元素或新插入的元素返回一个迭代器

map<Foo*, string>::iterator it;
it = my_map.find(foo_obj);   // 1st lookup

my_map.insert( map<Foo*, string>::value_type(foo_obj, "some_value") );
map::迭代器;
it=my_map.find(foo_obj);//第一次查找
my_map.insert(map::value_type(foo_obj,“some_value”);
这样做的好处是简单。主要缺点是,无论是否需要插入,您总是为第二个参数构造一个新值。对于字符串,这可能无关紧要。如果你的价值是昂贵的建设这可能是浪费比必要的

解决这个问题的一种方法是使用insert的“提示”版本

std::pair< map<foo*, string>::iterator, map<foo*, string>::iterator >
    range = my_map.equal_range(foo_obj);

if (range.first == range.second)
{
    if (range.first != my_map.begin())
        --range.first;

    my_map.insert(range.first, map<Foo*, string>::value_type(foo_obj, "some_value") );
}
std::pair
范围=我的地图。相等范围(foo\u obj);
if(range.first==range.second)
{
if(range.first!=my_map.begin())
--范围:第一;
my_map.insert(range.first,map::value_type(foo_obj,“some_value”);
}
只有在元素紧跟在所提供的迭代器之后插入时,才能保证插入时间为固定摊销时间,因此如果可能的话,插入时间为
--

编辑


如果这需要
--
看起来很奇怪,那么它就是。标准中有一个公开缺陷(233)突出了该问题,尽管在重复问题中,该问题适用于
map
的描述更清晰。

在您的示例中,您希望在找不到该问题时插入。如果默认构造和设置之后的值并不昂贵,我建议使用1查找的更简单版本:

string& r = my_map[foo_obj];    // only lookup & insert if not existed
if (r == "") r = "some value";  // if default (obj wasn't in map), set value
                                // else existed already, do nothing

如果你的例子说明了你真正想要的,考虑把这个值添加为<代码> STR Fo::S/<代码>,你已经有了这个对象,所以不需要查找,只是检查它是否有默认值。并将OBJ保存在

std::set
中。甚至使用Value2扩展
类FooWith2
也可能比使用
map
更便宜


但是,如果确实需要通过映射这样连接数据,或者如果您只想在数据存在时进行更新,那么Jonathan会给出答案。

ok,因此这确实是唯一的方法,操作符[]的上一条注释是错误的(如果键已经在映射中,它会覆盖上一个键/值对)提示版本不适用于hash_映射,但对于映射,它可能比为我的get_else_计算定义lambda更简单,在这里,我默认构造然后修改返回的迭代器值(当然,您可以在没有lambda的情况下内联执行该操作)。通过hash_映射,我想我指的是tr1或C++0x.True中的std::unordered_映射,如果插入发生在提示之前,那么提示不能保证在固定时间内摊销,这也让我感到很不舒服,因为这将在容器的开始和结束时起作用如果插入点紧跟在何处之前或之后,则插入可以在摊销固定时间内进行,而不是在对数时间内进行
map<Foo*, string>::iterator it;
it = my_map.find(foo_obj);   // 1st lookup

my_map.insert( map<Foo*, string>::value_type(foo_obj, "some_value") );
std::pair< map<foo*, string>::iterator, map<foo*, string>::iterator >
    range = my_map.equal_range(foo_obj);

if (range.first == range.second)
{
    if (range.first != my_map.begin())
        --range.first;

    my_map.insert(range.first, map<Foo*, string>::value_type(foo_obj, "some_value") );
}
string& r = my_map[foo_obj];    // only lookup & insert if not existed
if (r == "") r = "some value";  // if default (obj wasn't in map), set value
                                // else existed already, do nothing