[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()函数,并且如果你想查找元素(通过键)并为它指定一些元素 - 使用operator []。

为了简化插入使用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 );



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

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”上显示没有错误的事实;“ 会产生毁灭性的影响!




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

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%的时间。






Links