일상+자잘한 일

[C++] set operator 사용 시 const가 필요한 이유

높은곳에영광 2023. 10. 12. 14:24

백준 문제를 풀다가 신기한 것을 발견했다.

vector나 배열의 비교 연산자를 오버로딩할 때는 const가 없어도 컴파일 오류가 없었는데, set의 비교 연산자를 오버로딩하려고 하니 const가 없을 때만 컴파일 오류가 나는 것을 확인했다.

 

내가 짠 코드는 아래와 같다. 분명 로컬 vscode에서는 이상 없이 컴파일 됐는데 컴파일 오류가 나서 당황스러웠다.

#include <iostream>
#include <set>
using namespace std ;

struct cmp
{
	//여기 const가 없으면 컴파일 오류가 났다.
    bool operator()(string a, string b) const {
        if(a.length() == b.length()) return a < b ;
        return a.length() < b.length() ;
    }
};

int main()
{
    int N ;
    cin >> N ;
    set<string, cmp> s ;
    string str ;

    for(int i = 0 ; i < N ; i++) {
        cin >> str ;
        s.insert(str) ;
    }

    for(auto str : s)
        cout << str << "\n" ;
}

조사해보니 이유는 단순한데 set의 member는 모두 const로 선언되서다.

set의 경우 red-black tree 구조로 되어있고 삽입과 동시에 순서를 정렬한다. 이러한 자료구조 때문에 안에 데이터가 변경되면 어떻게 변경되었는지 확인하기 어렵고 수정도 까다롭기 때문에 멤버 변수의 값 변경을 막기 위해 const로 선언되어있다.

 

따라서 operator를 멤버함수로 정의하기 위해 const가 필수적으로 필요하며 없으면 오류가 나는 것이다.

 

[참고 자료]

 

Why STL <set> the overload operator < function must be a const function?

class Test { public: int v; Test(int s) { v = s; } bool operator < (const Test & b) const { return v < b.v; } }; int main() { set <T...

stackoverflow.com

 

https://cplusplus.com/reference/set/set/

difference_typea signed integral type, identical to: iterator_traits ::difference_type usually the same as ptrdiff_t

cplusplus.com

 

std::set<Key,Compare,Allocator>::set - cppreference.com

(1) set(); (until C++11) set()    : set(Compare()) {} (since C++11) explicit set( const Compare& comp,               const Allocator& alloc = Allocator() ); (2) explicit set( const Allocator& alloc ); (3) (since C++11) template< class InputIt > se

en.cppreference.com