map이나 multimap 등의 [] 연산자는 두가지 동작을 같는다. 첫번째는 해당 키값의 데이타를 갱신하는 것이고 두번째로 해당 키값의 데이타가 컨테이너에 존재하지 않는다면 추가를 하는 동작이다.

map이나 multimap 등의 [] 연산자는 두가지 동작을 같는다. 첫번째는 해당 키값의 데이타를 갱신하는 것이고 두번째로 해당 키값의 데이타가 컨테이너에 존재하지 않는다면 추가를 하는 동작이다.

문제는 추가를 하는 동작에서의 불필요한 오버해드이다.
이 오버헤드는 일반적으로 기본생성자가 아닌 특정 데이타 타입을 지원의 생성자를 지원하는 클래스에서 문제가 되는데
class Widget{
public:
Widget();
Widget(double weight);
Widget& operator=(double weight);
}
같은 식으로 선언된 클래스의 경우
map<int, Widget> m;
m[1] = 1.50;
위의 코드는 실질적으로 기본 생성자를 통해서 임시 Widget 변수를 생성하고 그걸 map에 추가하고 그 후에 키값이 1인 항목을 찾아 수정하는 과정을 거치게 된다.
typedef map<int, Widget> IntWidgetMap;
pair<IntWidgetMap::iterator, bool> result = m.insert(IntWidgetMap::value_type(1, Widget()));
result.first->second = 1.50;
Widget 객체를 임시로 만드는데 필요한 기본 생성자 함수, 이것을 없에는 대 필요한 소멸자 함수, 그리고 Widget의 대입 연산자 함수가 추가 적으로 호출된다.

[] 연산으로 삽입이 될경우 이런 오버헤드를 얻게 될수 있지만 명시적으로 insert를 사용한다면 해당 오버해드를 줄일수 있다.
m.insert(IntWidgetMap::value_type(1,1.50));

insert 함수를 이용한 갱신을 할경우는 위와는 반대의 일이 일어난다. insert함수를 위한 추가적인 생성자가 호출되고 이후 대입연산이 이루어 진다.
// [] 연산자를 이용한 갱신
m[k] = v;

// insert를 이용한 갱신
m.insert(IntWidgetMap::value_type(k,v)).first->second = v;


결론을 내리자면 map에서 insert와 [] 적절한 위치에 사용을 해야 하며 만약 해당 키값의 데이타가 존재하는지 모를 경우에는 lower_bound 등의 검색함수를 이용하여 해당 데이타가 존재하지 않는다면 insert를 호출, 존재한다면 갱신하는 루틴을 작성하도록 한다.
(lower_bound 의 리턴값은 약간 특이. EffectiveSTL45 참조)

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다