C++ STL에서 제공하는 set은 데이터를 항상 정렬된 상태로 유지하며, 중복 요소를 허용하지 않는 특수한 연관 컨테이너입니다. 기본적으로 int, double 같은 기본 자료형은 별도 설정 없이 바로 사용할 수 있지만, 직접 만든 클래스나 구조체 같은 사용자 정의 데이터 타입을 저장하려면 추가 작업이 필요합니다.
사용자 정의 타입에 필요한 조건: operator< 오버로딩
set은 내부적으로 요소들을 정렬하기 위해 비교 연산을 수행합니다. 따라서 사용자 정의 타입을 set에 넣으려면 해당 클래스에 operator<(보다 작음 연산자)를 오버로딩하여, 두 객체를 비교할 수 있는 기준을 반드시 제공해야 합니다.
만약 이 연산자가 정의되어 있지 않으면, set은 두 객체의 대소 관계를 판단할 수 없어 정렬 순서를 결정하지 못하고 컴파일 오류가 발생합니다. 아래 예제에서는 학생(Student) 객체를 학번(id)을 기준으로 정렬하도록 구현했습니다.
예제 코드
#include <iostream>
#include <set>
using namespace std;
class Student {
int id, marks;
public:
Student(int id, int marks) {
this->id = id;
this->marks = marks;
}
// 학번(id)을 기준으로 정렬하기 위한 비교 연산자 오버로딩
bool operator<(const Student& st) const {
return (this->id < st.id);
}
void display() const {
cout << "(" << id << ", " << marks << ")\n";
}
};
int main() {
Student s1(5, 70), s2(3, 86), s3(2, 91),
s4(2, 60), s5(1, 78), s6(6, 53), s7(4, 59);
// 학번(id)이 중복되는 객체는 삽입되지 않음
set<Student> st_set;
st_set.insert(s1);
st_set.insert(s2);
st_set.insert(s3);
st_set.insert(s4);
st_set.insert(s5);
st_set.insert(s6);
st_set.insert(s7);
set<Student>::iterator it;
for (it = st_set.begin(); it != st_set.end(); it++) {
it->display();
}
}실행 결과
(1, 78) (2, 91) (3, 86) (4, 59) (5, 70) (6, 53)
코드 설명 및 주요 포인트
위 예제에는 총 7개의 Student 객체를 삽입했지만, 출력 결과는 6개뿐입니다. 그 이유는 s3(2, 91)과 s4(2, 60)처럼 학번(id)이 동일한 객체가 존재하기 때문입니다. set은 비교 연산자를 기준으로 중복을 판단하므로, id가 같으면 점수(marks)가 다르더라도 하나의 요소만 저장됩니다.
정렬 기준으로 사용할 멤버 변수는 개발자가 자유롭게 선택할 수 있습니다. 예를 들어 this->marks < st.marks로 수정하면 점수를 기준으로 정렬됩니다. 또한 operator<를 const 멤버 함수로 선언해야 set 내부에서 안전하게 호출할 수 있으므로, 함수 끝에 const 키워드를 붙이는 것도 잊지 말아야 합니다.
이처럼 C++의 set은 비교 연산자만 적절히 정의해주면 어떤 사용자 정의 타입이든 자동으로 정렬되고 중복 없이 관리할 수 있는 강력한 도구입니다.