STL 맵에서 map :: insert를 사용하는 것이 []보다 낫습니까?
얼마 전에 STL 맵에 값을 삽입하는 방법에 대해 동료와 토론했습니다 . 나는 map[key] = value;
그것이 자연스럽고 읽기 쉽기 때문에 선호했습니다.map.insert(std::make_pair(key, value))
나는 방금 그에게 물었고 우리 중 어느 쪽도 insert가 더 나은 이유를 기억할 수는 없지만 그것이 스타일 선호가 아니라 효율성과 같은 기술적 이유가 있다고 확신합니다. SGI의 STL 참조는 단순히 "엄밀히 말하면이이 멤버 함수가 필요하지 않습니다. : 그것은 단지 편의를 위해 존재한다"라는
아무도 그 이유를 말해 줄 수 있습니까, 아니면 하나가 있다고 꿈꾸고 있습니까?
당신이 쓸 때
map[key] = value;
이 같은 경우 알 수있는 방법은 없습니다 교체value
대한이 key
, 또는 당신이 경우 생성 된 새로운를 key
함께 value
.
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;
}
대부분의 내 앱에서는 일반적으로 생성 또는 교체 여부를 신경 쓰지 않으므로 더 읽기 쉽습니다 map[key] = value
.
맵에 이미 존재하는 키와 관련하여 두 가지 의미가 다릅니다. 그래서 그들은 실제로 직접 비교할 수 없습니다.
그러나 operator [] 버전은 기본적으로 값을 구성한 다음 할당하는 것이 필요하므로 복사 비용보다 비싸면 비용이 더 많이 듭니다. 때로는 기본 구성이 의미가 없으므로 operator [] 버전을 사용하는 것이 불가능합니다.
주목해야 할 또 다른 사항 std::map
:
myMap[nonExistingKey];
지도 nonExistingKey
에 기본값 으로 초기화 된 새 항목을 만듭니다 .
이것은 내가 그것을 처음 보았을 때 지옥에서 나에게 두려움을주었습니다. 예상하지 못했을 것입니다. 나에게는 그것이 get 작업처럼 보이며 나는 "부작용"을 기대하지 않았다. map.find()
지도에서 나올 때 선호 하십시오.
기본 생성자의 성능 적중이 문제가되지 않으면 신을 사랑하기 위해 더 읽기 쉬운 버전으로 이동하십시오.
:)
insert
예외 안전의 관점에서 더 좋습니다.
이 표현 map[key] = value
은 실제로 두 가지 연산입니다.
map[key]
-기본값으로지도 요소를 만듭니다.= value
-해당 요소에 값을 복사합니다.
두 번째 단계에서 예외가 발생할 수 있습니다. 결과적으로 작업은 부분적으로 만 수행됩니다 (새 요소가 맵에 추가되었지만 해당 요소는로 초기화되지 않았습니다 value
). 작업이 완료되지 않았지만 시스템 상태가 수정 된 상황을 "부작용"이있는 작업이라고합니다.
insert
작업은 강력한 보증을 제공하며 부작용이 없음을 의미합니다 ( https://en.wikipedia.org/wiki/Exception_safety ). insert
완전히 완료되었거나 맵을 수정되지 않은 상태로 둡니다.
http://www.cplusplus.com/reference/map/map/insert/ :
단일 요소를 삽입하는 경우 예외가 발생할 경우 컨테이너가 변경되지 않습니다 (강력 보장).
응용 프로그램이 속도가 중요한 경우 [] 연산자를 사용하여 조언합니다. 원래 객체의 총 3 복사본을 생성하고 그중 2 개는 임시 객체이며 조만간 파괴됩니다.
그러나 insert ()에서 원래 오브젝트의 사본 4 개가 작성되고 그 중 3 개는 임시 오브젝트 (필수 "임시"일 필요는 없음)이며 소멸됩니다.
1. 한 개의 객체 메모리 할당 2. 한 개의 추가 생성자 호출 3. 한 개의 추가 소멸자 호출 4. 한 개의 개체 메모리 할당 해제
객체가 크면 생성자가 일반적이며 소멸자는 많은 리소스 확보를 수행하며 포인트 이상은 더 중요합니다. 가독성에 관해서는, 나는 둘 다 공평하다고 생각합니다.
같은 질문이 내 마음에 들었지만 가독성이 아니라 속도입니다. 여기 내가 언급 한 요점에 대해 알게 된 샘플 코드가 있습니다.
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;
}
Now in c++11 I think that the best way to insert a pair in a STL map is:
typedef std::map<int, std::string> MyMap;
MyMap map;
auto& result = map.emplace(3,"Hello");
The result will 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.
PS: If you don´t case about the order you can use std::unordered_map ;)
Thanks!
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.
One note is that you can also use 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);
}
Here's another example, showing that operator[]
overwrites the value for the key if it exists, but .insert
does not overwrite the value if it exists.
void mapTest()
{
map<int,float> m;
for( int i = 0 ; i <= 2 ; i++ )
{
pair<map<int,float>::iterator,bool> result = m.insert( make_pair( 5, (float)i ) ) ;
if( result.second )
printf( "%d=>value %f successfully inserted as brand new value\n", result.first->first, result.first->second ) ;
else
printf( "! The map already contained %d=>value %f, nothing changed\n", result.first->first, result.first->second ) ;
}
puts( "All map values:" ) ;
for( map<int,float>::iterator iter = m.begin() ; iter !=m.end() ; ++iter )
printf( "%d=>%f\n", iter->first, iter->second ) ;
/// now watch this..
m[5]=900.f ; //using operator[] OVERWRITES map values
puts( "All map values:" ) ;
for( map<int,float>::iterator iter = m.begin() ; iter !=m.end() ; ++iter )
printf( "%d=>%f\n", iter->first, iter->second ) ;
}
This is a rather restricted case, but judging from the comments I've received I think it's worth noting.
I've seen people in the past use maps in the form of
map< const key, const val> Map;
to evade cases of accidental value overwriting, but then go ahead writing in some other bits of code:
const_cast< T >Map[]=val;
Their reason for doing this as I recall was because they were sure that in these certain bits of code they were not going to be overwriting map values; hence, going ahead with the more 'readable' method []
.
I've never actually had any direct trouble from the code that was written by these people, but I strongly feel up until today that risks - however small - should not be taken when they can be easily avoided.
In cases where you're dealing with map values that absolutely must not be overwritten, use insert
. Don't make exceptions merely for readability.
The fact that std::map insert()
function doesn't overwrite value associated with the key allows us to write object enumeration code like this:
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:
string word;
map<string, size_t> dict;
while(getline(cin, word)) {
size_t sz = dict.size();
if (!dict.count(word))
dict[word] = sz;
}
참고 URL : https://stackoverflow.com/questions/326062/in-stl-maps-is-it-better-to-use-mapinsert-than
'Programing' 카테고리의 다른 글
ADT에 'org.eclipse.wst.sse.core 0.0.0'이 필요하지만 찾을 수 없습니다 (0) | 2020.05.09 |
---|---|
Linux에서 세그멘테이션 오류로 코어 덤프를 생성하는 방법은 무엇입니까? (0) | 2020.05.09 |
mockMvc를 사용하여 응답 본문에서 문자열을 확인하는 방법 (0) | 2020.05.08 |
루비 젬을 업그레이드하는 방법 (0) | 2020.05.08 |
ASP.Net MVC에서 Access-Control-Allow-Origin 설정-가장 간단한 방법 (0) | 2020.05.08 |