C++ 在 STL 映射中,使用 map::insert 是否比使用 [] 更好?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/326062/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In STL maps, is it better to use map::insert than []?
提问by danio
A while ago, I had a discussion with a colleague about how to insert values in STL maps. I preferred
map[key] = value;
because it feels natural and is clear to read whereas he preferred
map.insert(std::make_pair(key, value))
前阵子和同事讨论了如何在STL maps中插入值。我更喜欢,
map[key] = value;
因为它感觉自然并且清晰易读,而他更喜欢
map.insert(std::make_pair(key, value))
I just asked him and neither of us can remember the reason why insert is better, but I am sure it was not just a style preference rather there was a technical reason such as efficiency. The SGI STL referencesimply says "Strictly speaking, this member function is unnecessary: it exists only for convenience."
我刚刚问过他,我们都不记得为什么 insert 更好的原因,但我确信这不仅仅是一种风格偏好,而是有一个技术原因,比如效率。在SGI STL参考只是说“严格地说,这个成员函数是不必要的:它的存在只是为了方便。”
Can anybody tell me that reason, or am I just dreaming that there is one?
谁能告诉我这个原因,还是我只是在梦想有一个?
回答by netjeff
When you write
当你写
map[key] = value;
there's no way to tell if you replacedthe value
for key
, or if you createda new key
with value
.
有没有办法告诉你,如果更换了value
为key
,或者如果你创建了一个新的key
用value
。
map::insert()
will only create:
map::insert()
只会创建:
using std::cout; using std::endl;
typedef std::map<int, std::string> MyMap;
MyMap map;
// ...
std::pair<MyMap::iterator, bool> res = map.insert(MyMap::value_type(key,value));
if ( ! res.second ) {
cout << "key " << key << " already exists "
<< " with value " << (res.first)->second << endl;
} else {
cout << "created key " << key << " with value " << value << endl;
}
For most of my apps, I usually don't care if I'm creating or replacing, so I use the easier to read map[key] = value
.
对于我的大多数应用程序,我通常不在乎我是在创建还是替换,所以我使用更容易阅读的map[key] = value
.
回答by Greg Rogers
The two have different semantics when it comes to the key already existing in the map. So they aren't really directly comparable.
当涉及到映射中已经存在的键时,两者具有不同的语义。所以它们实际上并没有直接的可比性。
But the operator[] version requires default constructing the value, and then assigning, so if this is more expensive then copy construction, then it will be more expensive. Sometimes default construction doesn't make sense, and then it would be impossible to use the operator[] version.
但是 operator[] 版本需要默认构造值,然后赋值,所以如果这比复制构造更昂贵,那么它会更昂贵。有时默认构造没有意义,然后就不可能使用 operator[] 版本。
回答by Hawkeye Parker
Another thing to note with std::map
:
另一件需要注意的事情std::map
:
myMap[nonExistingKey];
will create a new entry in the map, keyed to nonExistingKey
initialized to a default value.
myMap[nonExistingKey];
将在地图中创建一个新条目,键控为nonExistingKey
初始化为默认值。
This scared the hell out of me the first time I saw it (while banging my head against a nastly legacy bug). Wouldn't have expected it. To me, that looks like a get operation, and I didn't expect the "side-effect." Prefer map.find()
when getting from your map.
当我第一次看到它时,这把我吓坏了(同时我的头撞到了一个讨厌的遗留错误)。没想到吧。对我来说,这看起来像是一个 get 操作,我没想到会有“副作用”。不想map.find()
从你的地图时获得。
回答by Torlack
If the performance hit of the default constructor isn't an issue, the please, for the love of god, go with the more readable version.
如果默认构造函数的性能影响不是问题,那么为了上帝的爱,请选择更具可读性的版本。
:)
:)
回答by anton_rh
insert
is better from the point of exception safety.
insert
从异常安全的角度来看更好。
The expression map[key] = value
is actually two operations:
表达式map[key] = value
实际上是两个操作:
map[key]
- creating a map element with default value.= value
- copying the value into that element.
map[key]
- 创建具有默认值的地图元素。= value
- 将值复制到该元素中。
An exception may happen at the second step. As result the operation will be only partially done (a new element was added into map, but that element was not initialized with value
). The situation when an operation is not complete, but the system state is modified, is called the operation with "side effect".
第二步可能会发生异常。因此,操作将仅部分完成(一个新元素被添加到地图中,但该元素没有用 初始化value
)。操作未完成,但系统状态被修改的情况,称为有“副作用”的操作。
insert
operation gives a strong guarantee, means it doesn't have side effects (https://en.wikipedia.org/wiki/Exception_safety). insert
is either completely done or it leaves the map in unmodified state.
insert
操作提供了强有力的保证,意味着它没有副作用(https://en.wikipedia.org/wiki/Exception_safety)。insert
要么完全完成,要么使地图处于未修改状态。
http://www.cplusplus.com/reference/map/map/insert/:
http://www.cplusplus.com/reference/map/map/insert/:
If a single element is to be inserted, there are no changes in the container in case of exception (strong guarantee).
如果要插入单个元素,则在异常情况下容器不会发生变化(强保证)。
回答by Rampal Chaudhary
If your application is speed critical i will advice using [] operator because it creates total 3 copies of the original object out of which 2 are temporary objects and sooner or later destroyed as.
如果您的应用程序对速度至关重要,我会建议使用 [] 运算符,因为它创建了原始对象的 3 个副本,其中 2 个是临时对象,迟早会被销毁。
But in insert(), 4 copies of the original object are created out of which 3 are temporary objects( not necessarily "temporaries") and are destroyed.
但是在 insert() 中,创建了原始对象的 4 个副本,其中 3 个是临时对象(不一定是“临时对象”)并被销毁。
Which means extra time for: 1. One objects memory allocation 2. One extra constructor call 3. One extra destructor call 4. One objects memory deallocation
这意味着额外的时间用于: 1. 一个对象内存分配 2. 一个额外的构造函数调用 3. 一个额外的析构函数调用 4. 一个对象内存释放
If your objects are large, constructors are typical, destructors do a lot of resource freeing, above points count even more. Regarding readability, i think both are fair enough.
如果您的对象很大,则构造函数是典型的,析构函数会释放大量资源,以上几点更重要。关于可读性,我认为两者都足够公平。
The same question came into my mind but not over readability but speed. Here is a sample code through which I came to know about the point i mentioned.
同样的问题出现在我的脑海中,但不是关于可读性而是速度。这是一个示例代码,通过它我开始了解我提到的这一点。
class Sample
{
static int _noOfObjects;
int _objectNo;
public:
Sample() :
_objectNo( _noOfObjects++ )
{
std::cout<<"Inside default constructor of object "<<_objectNo<<std::endl;
}
Sample( const Sample& sample) :
_objectNo( _noOfObjects++ )
{
std::cout<<"Inside copy constructor of object "<<_objectNo<<std::endl;
}
~Sample()
{
std::cout<<"Destroying object "<<_objectNo<<std::endl;
}
};
int Sample::_noOfObjects = 0;
int main(int argc, char* argv[])
{
Sample sample;
std::map<int,Sample> map;
map.insert( std::make_pair<int,Sample>( 1, sample) );
//map[1] = sample;
return 0;
}
回答by GutiMac
Now in c++11 I think that the best way to insert a pair in a STL map is:
现在在 c++11 中,我认为在 STL 映射中插入一对的最佳方法是:
typedef std::map<int, std::string> MyMap;
MyMap map;
auto& result = map.emplace(3,"Hello");
The resultwill be a pair with:
该结果将是具有一对:
First element (result.first), points to the pair inserted or point to the pair with this key if the key already exist.
Second element (result.second), true if the insertion was correct or false it something went wrong.
第一个元素(result.first),指向插入的对,或者如果键已经存在,则指向具有该键的对。
第二个元素(result.second),如果插入正确或错误则为真,则表示出现问题。
PS: If you don′t case about the order you can use std::unordered_map ;)
PS:如果你不关心订单,你可以使用 std::unordered_map ;)
Thanks!
谢谢!
回答by Anthony Cramp
A gotcha with map::insert() is that it won't replace a value if the key already exists in the map. I've seen C++ code written by Java programmers where they have expected insert() to behave the same way as Map.put() in Java where values are replaced.
map::insert() 的一个问题是,如果键已经存在于映射中,它不会替换值。我见过由 Java 程序员编写的 C++ 代码,他们希望 insert() 的行为与 Java 中的 Map.put() 相同,其中值被替换。
回答by rlbond
One note is that you can also use Boost.Assign:
一个注意事项是您还可以使用Boost.Assign:
using namespace std;
using namespace boost::assign; // bring 'map_list_of()' into scope
void something()
{
map<int,int> my_map = map_list_of(1,2)(2,3)(3,4)(4,5)(5,6);
}
回答by mechatroner
The fact that std::map insert()
function doesn't overwrite value associated with the key allows us to write object enumeration code like this:
std::mapinsert()
函数不会覆盖与键关联的值这一事实使我们能够编写这样的对象枚举代码:
string word;
map<string, size_t> dict;
while(getline(cin, word)) {
dict.insert(make_pair(word, dict.size()));
}
It's a pretty common problem when we need to map different non-unique objects to some id's in range 0..N. Those id's can be later used, for example, in graph algorithms. Alternative with operator[]
would look less readable in my opinion:
当我们需要将不同的非唯一对象映射到 0..N 范围内的某些 id 时,这是一个非常常见的问题。这些 id 可以在以后使用,例如,在图形算法中。operator[]
在我看来,替代方式看起来不太可读:
string word;
map<string, size_t> dict;
while(getline(cin, word)) {
size_t sz = dict.size();
if (!dict.count(word))
dict[word] = sz;
}