5 min to read
객체지향프로그래밍(25) - explicit 키워드와 mutable 키워드
explicit, mutable 키워드 이해

🔚 짧게 하는 복습
✅ 1. 기본 연산자와 클래스 간의 형변환 방법을 안다.
✅ 2. 다른 클래스 간의 형변환 방법을 모두 알고, 그 특징을 안다.
혹시 기억이 안 난다면, 다시 돌아가자
지금까지 오버로딩 및 형변환에 다루면서, 지속해서 제기되었던 문제가 있다.
바로 묵시적 형변환이다.
이는 우리가 원하지 않는 방향으로 코드가 진행될 수 있음을 뜻한다.
이 경우가 최악의 상황인데 에러 하나 없이 돌아가는데 의도치 않는 결과가 나와서 어디가 틀리는지도 모르게 된다.
오늘은 이를 막아주는 explicit 키워드와 또 다른 키워드 mutable에 대해서 다루겠다.
explicit이란?
묵시적 형변환이 문제를 일으키는 코드를 하나 같이 보겠다.
위 코드가 컴파일(실행 전에) 에러를 일으키는가? 아니다.
위 코드가 런타임(실행 시간에) 에러를 일으키는가? 그것도 아니다.
그런데 의도치 않은 상황이 발생했는가? 그렇다.
분명 들어가면 안 될 것이 들어갔는데, 코드가 실행되었다.
이런 것을 막기 위한 키워드가 explicit이다.
explicit이란 한국어로 변환하면 명시적이란 뜻으로, 말 그대로 의도치 않은 묵시적 변환이 일어날 것 같으면 오류를 나타내는 키워드이다.
저기서 아래 코드처럼 1변수 생성자에 explicit을 넣으면, 함수 호출 과정에서 오류를 던져준다.
explicit counter(int _count) : count(_count) {}
결과
solution.cpp:22:13: error: could not convert '3' from 'int' to 'counter'
22 | display(3);
| ^
| |
| int
이 키워드가 왜 필요하냐면, 묵시적 변환으로 인한 오류를 컴파일 시간에 잡을 수 있기 때문이다.
언급했던 것처럼 컴파일에도 런타임에도 잡히지 않는 오류를 몇 시간 동안 코드를 뒤지는 것은 정말 힘들기 때문이다.
유일한 단점이라 하면, 대입 연산자를 통한 일 변수 생성자를 쓰지 못한다는 점 정도가 있다
그러나, 사실 위의 이점에 비해서 이 정도 단점은 아무것도 아니다.
mutable 키워드
mutable 키워드란 const로 생성된 객체나 메소드에서 특정 멤버만 수정할 수 있는 권한을 주는 키워드이다.
사실 본인도 공부하면서 지금까지 이 설명보다 이해가 잘 되는 것이 없어서, 이번만큼만 출처를 남기고 원문을 가져와 보겠다. (출처 : 더 읽어보기)
먼저 멤버 함수를 왜 const 로 선언하는지 부터 생각해봅시다. 클래스의 멤버 함수들은 이 객체는 이러이러한 일을 할 수 있습니다 라는 의미를 나타내고 있습니다.
그리고 멤버 함수를 const 로 선언하는 의미는 이 함수는 객체의 내부 상태에 영향을 주지 않습니다 를 표현하는 방법 입니다. 대표적인 예로 읽기 작업을 수행하는 함수들을 들 수 있습니다.
대부분의 경우 의미상 상수 작업을 하는 경우, 실제로도 상수 작업을 하게 됩니다. 하지만, 실제로 꼭 그렇지만은 않습니다. 예를 들어서 아래와 같은 서버 프로그램을 만든다고 해봅시다.
class Server {
// .... (생략) ....
// 이 함수는 데이터베이스에서 user_id 에 해당하는 유저 정보를 읽어서 반환한다.
User GetUserInfo(const int user_id) const {
// 1. 데이터베이스에 user_id 를 검색
Data user_data = Database.find(user_id);
// 2. 리턴된 정보로 User 객체 생성
return User(user_data);
}
};
이 서버에는 GetUserInfo 라는 함수가 있는데 입력 받은 user_id 로 데이터베이스에서 해댱 유저를 조회해서 그 유저의 정보를 리턴하는 함수 입니다. 당연히도 데이터베이스를 업데이트 하지도 않고, 무언가 수정하는 작업도 당연히 없기 때문에 const 함수로 선언되어 있습니다.
그런데 대개 데이터베이스에 요청한 후 받아오는 작업은 꽤나 오래 걸립니다. 그래서 보통 서버들의 경우 메모리에 캐쉬(cache)를 만들어서 자주 요청되는 데이터를 굳이 데이터베이스까지 가서 찾지 않아도 메모리에서 빠르게 조회할 수 있도록 합니다.
물론 캐쉬는 데이터베이스만큼 크지 않기 때문에 일부 유저들 정보 밖에 포함하지 않습니다. 따라서 캐쉬에 해당 유저가 없다면 (이를 캐쉬 미스-cache miss 라고 합니다), 데이터베이스에 직접 요청해야겠지요. 대신 데이터베이스에서 유저 정보를 받으면 캐쉬에 저장해놓아서 다음에 요청할 때는 빠르게 받을 수 있게 됩니다.
보통 한 번 요청된 정보는 계속해서 요청될 확률이 높기때문에 캐쉬에 넣게 됩니다. 물론 캐쉬 크기는 한정적이니까 이전에 오래된 캐쉬부터 지우게됩니다. 이를 구현한다면 아래와 같겠지요.
class Server {
// .... (생략) ....
Cache cache; // 캐쉬!
// 이 함수는 데이터베이스에서 user_id 에 해당하는 유저 정보를 읽어서 반환한다.
User GetUserInfo(const int user_id) const {
// 1. 캐쉬에서 user_id 를 검색
Data user_data = cache.find(user_id);
// 2. 하지만 캐쉬에 데이터가 없다면 데이터베이스에 요청
if (!user_data) {
user_data = Database.find(user_id);
// 그 후 캐쉬에 user_data 등록
cache.update(user_id, user_data); // <-- 불가능
}
// 3. 리턴된 정보로 User 객체 생성
return User(user_data);
}
};
그런데 문제는 GetUserInfo 가 const 함수라는 점입니다. 따라서
cache.update(user_id, user_data); // <-- 불가능
위 처럼 캐쉬를 업데이트 하는 작업을 수행할 수 없습니다. 왜냐하면 캐쉬를 업데이트 한다는 것은 케쉬 내부의 정보를 바꿔야 된다는 뜻이기 때문이죠. 따라서 저 update 함수는 const 함수가 아닐 것입니다.
그렇다고 해서 GetUserInfo 에서 const 를 떼기도 좀 뭐한것이, 이 함수를 사용하는 사용자의 입장에선 당연히 const 로 정의되어야 하는 함수 이기 때문이지요. 따라서 이 경우, Cache 를 mutable 로 선언해버리면 됩니다.
mutable Cache cache; // 캐쉬!
위 처럼 말이지요. 이렇듯, mutable 키워드는 const 함수 안에서 해당 멤버 변수에 const 가 아닌 작업을 할 수 있게 만들어줍니다.
문제가 될 시 삭제하겠습니다!🥹
📖 오늘의 핵심(다 알기 전까지는 넘어가지 말자❗)
✅ 1. explicit 키워드의 정의와 활용을 안다.
✅ 2. mutable 키워드의 정의와 활용을 안다.
⚠️ 복잡한 프로그램이나 오버 로딩을 많이 하게 되면 explicit 생성자를 최대한 활용하자.
💣 과제, 없음
🔜 더 공부해보기,
Comments