std::map::operator[]比std::map::insert更有效率?
std::map::operator[] is more efficient than std::map::insert?
我了解到 operator[] 等同于
(*((this->insert(make_pair(k,mapped_type()))).first)).second
因此,如果映射中不存在键,使用 operator[] 的效率低于使用 insert,对吗?因为还有一步,默认构造。
所以我写了一个demo来测试,像这样。
#include <iostream>
#include <map>
using namespace std;
static int id = 0;
class Foo
{
public:
Foo()
: _val(0)
{
_id = ++id;
cout << _id << " construct_no_param:" << _val << endl;
}
Foo(int val)
: _val(val)
{
_id = ++id;
cout << _id << " construct_has_param:" << _val << endl;
}
Foo(Foo &rhs)
: _val(rhs._val)
{
_id = ++id;
cout << _id << " construct_copy:" << _val << endl;
}
Foo(const Foo &rhs)
: _val(rhs._val)
{
_id = ++id;
cout << _id << " construct_const_copy:" << _val << endl;
}
Foo &operator=(Foo &rhs)
{
_val = rhs._val;
cout << _id << " assign:" << _val << endl;
}
Foo &operator=(const Foo &rhs)
{
_val = rhs._val;
cout << _id << " const_assign:" << _val << endl;
}
~Foo()
{
cout << _id << " destruct:" << _val << endl;
}
int _val;
int _id;
};
int main() {
map<int, Foo> m;
const Foo f(2);
cout << "-----" << endl;
// m[1] = f;
// m.insert(make_pair(1, f));
cout << "-----" << endl;
return 0;
}
首先,我使用了运算符[]
m[1] = f;
我得到了这个:
1 construct_has_param:2
-----
2 construct_no_param:0
3 construct_const_copy:0
4 construct_const_copy:0
3 destruct:0
2 destruct:0
4 assign:2
-----
1 destruct:2
4 destruct:2
然后,我用了insert
m.insert(make_pair(1, f));
我得到了这个:
1 construct_has_param:2
-----
2 construct_const_copy:2
3 construct_const_copy:2
4 construct_const_copy:2
5 construct_const_copy:2
4 destruct:2
3 destruct:2
2 destruct:2
-----
1 destruct:2
5 destruct:2
结果与我的预期不符。为什么 insert
有更多的结构?这是怎么回事?
顺便说一句,我使用 -O0 选项来禁用优化,但我不确定它是否有效。
gcc 版本 4.8.2 20131212(红帽 4.8.2-8)(GCC)
表达式 make_pair(1, f)
的类型为 std::pair<int, Foo>
,这不是您的映射 value_type
,而是 std::pair<const int, Foo>
,因此 std::pair<const int, Foo>
的参数中有一个副本=16=]。然后 map
内有 2 个副本,如果您的所有特殊成员没有抑制移动构造的生成,这将是移动。
如果您想尽可能避免复制,请使用 emplace
m.emplace(1, f);
并定义Foo
的移动构造函数和赋值
Foo(Foo &&rhs)
: _val(std::exchange(rhs.val, 0))
{
_id = ++id;
cout << _id << " move:" << _val << endl;
}
Foo& opeator=(Foo &&rhs)
{
std::swap(_val, rhs._val);
cout << _id << " move assign:" << _val << endl;
}
我还建议放弃 non-const 复制操作。
我了解到 operator[] 等同于
(*((this->insert(make_pair(k,mapped_type()))).first)).second
因此,如果映射中不存在键,使用 operator[] 的效率低于使用 insert,对吗?因为还有一步,默认构造。
所以我写了一个demo来测试,像这样。
#include <iostream>
#include <map>
using namespace std;
static int id = 0;
class Foo
{
public:
Foo()
: _val(0)
{
_id = ++id;
cout << _id << " construct_no_param:" << _val << endl;
}
Foo(int val)
: _val(val)
{
_id = ++id;
cout << _id << " construct_has_param:" << _val << endl;
}
Foo(Foo &rhs)
: _val(rhs._val)
{
_id = ++id;
cout << _id << " construct_copy:" << _val << endl;
}
Foo(const Foo &rhs)
: _val(rhs._val)
{
_id = ++id;
cout << _id << " construct_const_copy:" << _val << endl;
}
Foo &operator=(Foo &rhs)
{
_val = rhs._val;
cout << _id << " assign:" << _val << endl;
}
Foo &operator=(const Foo &rhs)
{
_val = rhs._val;
cout << _id << " const_assign:" << _val << endl;
}
~Foo()
{
cout << _id << " destruct:" << _val << endl;
}
int _val;
int _id;
};
int main() {
map<int, Foo> m;
const Foo f(2);
cout << "-----" << endl;
// m[1] = f;
// m.insert(make_pair(1, f));
cout << "-----" << endl;
return 0;
}
首先,我使用了运算符[]
m[1] = f;
我得到了这个:
1 construct_has_param:2
-----
2 construct_no_param:0
3 construct_const_copy:0
4 construct_const_copy:0
3 destruct:0
2 destruct:0
4 assign:2
-----
1 destruct:2
4 destruct:2
然后,我用了insert
m.insert(make_pair(1, f));
我得到了这个:
1 construct_has_param:2
-----
2 construct_const_copy:2
3 construct_const_copy:2
4 construct_const_copy:2
5 construct_const_copy:2
4 destruct:2
3 destruct:2
2 destruct:2
-----
1 destruct:2
5 destruct:2
结果与我的预期不符。为什么 insert
有更多的结构?这是怎么回事?
顺便说一句,我使用 -O0 选项来禁用优化,但我不确定它是否有效。
gcc 版本 4.8.2 20131212(红帽 4.8.2-8)(GCC)
表达式 make_pair(1, f)
的类型为 std::pair<int, Foo>
,这不是您的映射 value_type
,而是 std::pair<const int, Foo>
,因此 std::pair<const int, Foo>
的参数中有一个副本=16=]。然后 map
内有 2 个副本,如果您的所有特殊成员没有抑制移动构造的生成,这将是移动。
如果您想尽可能避免复制,请使用 emplace
m.emplace(1, f);
并定义Foo
的移动构造函数和赋值
Foo(Foo &&rhs)
: _val(std::exchange(rhs.val, 0))
{
_id = ++id;
cout << _id << " move:" << _val << endl;
}
Foo& opeator=(Foo &&rhs)
{
std::swap(_val, rhs._val);
cout << _id << " move assign:" << _val << endl;
}
我还建议放弃 non-const 复制操作。