[C++] 插入地图的首选/惯用方式


Answers

从C ++ 11开始,你有两个主要的附加选项。 首先,你可以使用insert()和list初始化语法:

function.insert({0, 42});

这在功能上等同于

function.insert(std::map<int, int>::value_type(0, 42));

但更简洁可读。 正如其他答案所指出的那样,这与其他形式相比有几个优点:

  • operator[]方法要求映射类型是可分配的,但情况并非总是如此。
  • operator[]方法可以覆盖现有元素,并且无法分辨是否发生了这种情况。
  • 您列出的insert的其他形式涉及隐式类型转换,这可能会减慢您的代码。

主要的缺点是,这种形式用来要求键和值是可复制的,所以它不适用于具有unique_ptr值的地图。 标准中已经修复了这个问题,但是修正可能还没有达到你的标准库实现。

其次,你可以使用emplace()方法:

function.emplace(0, 42);

这比insert()任何形式都要简洁,对于像unique_ptr这样的只移动的类型来说工作得很好,理论上可能稍微更有效率(尽管一个体面的编译器应该优化差异)。 唯一的缺点是可能会让读者感到惊讶,因为emplace方法通常不是这样使用的。

Question

我已经确定了插入std::map四种不同的方法:

std::map<int, int> function;

function[0] = 42;
function.insert(std::map<int, int>::value_type(0, 42));
function.insert(std::pair<int, int>(0, 42));
function.insert(std::make_pair(0, 42));

哪一种是首选/惯用的方式? (还有没有想过的另一种方式?)




如果要在std :: map中插入元素 - 使用insert()函数,并且如果要查找元素(通过键)并为其指定一些元素,请使用运算符[]。

为了简化插入使用boost :: assign库,像这样:

using namespace boost::assign;

// For inserting one element:

insert( function )( 0, 41 );

// For inserting several elements:

insert( function )( 0, 41 )( 0, 42 )( 0, 43 );



我已经在上述版本之间进行了一些比较:

function[0] = 42;
function.insert(std::map<int, int>::value_type(0, 42));
function.insert(std::pair<int, int>(0, 42));
function.insert(std::make_pair(0, 42));

发现插入版本之间的时间差异很小。

#include <map>
#include <vector>
#include <boost/date_time/posix_time/posix_time.hpp>
using namespace boost::posix_time;
class Widget {
public:
    Widget() {
        m_vec.resize(100);
        for(unsigned long it = 0; it < 100;it++) {
            m_vec[it] = 1.0;
        }
    }
    Widget(double el)   {
        m_vec.resize(100);
        for(unsigned long it = 0; it < 100;it++) {
            m_vec[it] = el;
        }
    }
private:
    std::vector<double> m_vec;
};


int main(int argc, char* argv[]) {



    std::map<int,Widget> map_W;
    ptime t1 = boost::posix_time::microsec_clock::local_time();    
    for(int it = 0; it < 10000;it++) {
        map_W.insert(std::pair<int,Widget>(it,Widget(2.0)));
    }
    ptime t2 = boost::posix_time::microsec_clock::local_time();
    time_duration diff = t2 - t1;
    std::cout << diff.total_milliseconds() << std::endl;

    std::map<int,Widget> map_W_2;
    ptime t1_2 = boost::posix_time::microsec_clock::local_time();    
    for(int it = 0; it < 10000;it++) {
        map_W_2.insert(std::make_pair(it,Widget(2.0)));
    }
    ptime t2_2 = boost::posix_time::microsec_clock::local_time();
    time_duration diff_2 = t2_2 - t1_2;
    std::cout << diff_2.total_milliseconds() << std::endl;

    std::map<int,Widget> map_W_3;
    ptime t1_3 = boost::posix_time::microsec_clock::local_time();    
    for(int it = 0; it < 10000;it++) {
        map_W_3[it] = Widget(2.0);
    }
    ptime t2_3 = boost::posix_time::microsec_clock::local_time();
    time_duration diff_3 = t2_3 - t1_3;
    std::cout << diff_3.total_milliseconds() << std::endl;

    std::map<int,Widget> map_W_0;
    ptime t1_0 = boost::posix_time::microsec_clock::local_time();    
    for(int it = 0; it < 10000;it++) {
        map_W_0.insert(std::map<int,Widget>::value_type(it,Widget(2.0)));
    }
    ptime t2_0 = boost::posix_time::microsec_clock::local_time();
    time_duration diff_0 = t2_0 - t1_0;
    std::cout << diff_0.total_milliseconds() << std::endl;

    system("pause");
}

这分别给出了版本(我跑了3次文件,因此连续3个时间差异):

map_W.insert(std::pair<int,Widget>(it,Widget(2.0)));

2198毫秒,2078毫秒,2072毫秒

map_W_2.insert(std::make_pair(it,Widget(2.0)));

2290ms,2037ms,2046ms

 map_W_3[it] = Widget(2.0);

2592毫秒,2278毫秒,2296毫秒

 map_W_0.insert(std::map<int,Widget>::value_type(it,Widget(2.0)));

2234ms,2031ms,2027ms

因此,不同插入版本之间的结果可以忽略不计(虽然没有进行假设检验)!

map_W_3[it] = Widget(2.0); 由于使用Widget的默认构造函数进行初始化,因此该示例需要大约10-15%的时间。




我只是稍微改变一点问题(字符串图)来显示插入的另一个兴趣:

std::map<int, std::string> rancking;

rancking[0] = 42;  // << some compilers [gcc] show no error

rancking.insert(std::pair<int, std::string>(0, 42));// always a compile error

编译器在“rancking [1] = 42;”上显示没有错误的事实 会产生毁灭性的影响!