[C++] explicit, mutable

·2023년 8월 20일
0

C++

목록 보기
8/17
post-custom-banner

암시적 변환(implicit conversion)

myString에 미리 크기를 할당 받는 새로운 생성자 추가

#include <iostream>

class myString
{
  char* string_content;  // 문자열 데이터를 가리키는 포인터
  int string_length;     // 문자열 길이

  int memory_capacity;

 public:
  // capacity 만큼 미리 할당함.
  myString(int capacity);
  
  myString(const char* str);
};

myString::myString(int capacity) 
{
  string_content = new char[capacity];
  string_length = 0;
  memory_capacity = capacity;
  std::cout << "Capacity : " << capacity << std::endl;
}

myString::myString(const char* str) 
{
  string_length = 0;
  while (str[string_length++]) 
  {
  }

  string_content = new char[string_length];
  memory_capacity = string_length;

  for (int i = 0; i != string_length; i++) string_content[i] = str[i];
}
void doSomethingWithString(myString s)
{
}

// 컴파일 가능
doSomethingWithString(myString("abc"));

// 컴파일 가능
// "abc"는 myString 타입은 아니지만 생성자 중 myString(const char* str)이 있으므로
// 컴파일러가 알아서 doSomethingWithString(myString("abc"))로 변환해서 컴파일 해줌
// -> 암시적 변환
doSomethingWithString("abc")

암시적 변환의 문제점

사용자의 실수로 doSomethingWithString 함수의 인자로 숫자를 전달하는 경우
컴파일러는 myString(int capacity)가 있으므로 오류로 판단하지 않음

// 컴파일 가능
// 컴파일러가 알아서 doSomethingWithString(myString(3))으로 변환해서 컴파일 해줌
doSomethingWithString(3); 

즉, 사용자가 의도하지 않은 암시적 변환이 일어나게 됨
-> 'explicit'로 원하지 않는 암시적 변환을 할 수 없도록 컴파일러에게 명시 가능


명시적 변환 (explicit conversion)

#include <iostream>

class myString 
{
  char* string_content;  // 문자열 데이터를 가리키는 포인터
  int string_length;     // 문자열 길이

  int memory_capacity;

 public:
  // capacity 만큼 미리 할당함. (explicit 키워드)
  explicit MyString(int capacity);

  // 문자열로 부터 생성
  MyString(const char* str);

  // 복사 생성자
  MyString(const MyString& str);

  ~MyString();

  int length() const;
  int capacity() const;
};

// 생략

void doSomethingWithString(myString s) 
{
  // Do something...
}

int main() 
{
  // 컴파일 오류 발생
  doSomethingWithString(3);
}

explicit은 implicit의 반대로 명시적이란 뜻을 가지고 있음
explicit 선언 시 이 생성자를 이용한 암시적 변환을 수행하지 못하게 막을 수 있음

// explicit 키워드를 사용하지 않은 경우 컴파일 오류 없이 작동 가능
myString s = "abc";  // MyString s("abc")
myString s = 5;      // MyString s(5)

// explicit 키워드를 사용한 경우 컴파일 오류 발생
myString s(5);   // 허용
myString s = 5;  // 컴파일 오류!

mutable

const 함수 내부에서는 멤버 변수들의 값을 바꾸는 것이 불가능
하지만 멤버 변수를 mutable로 선언하였다면 const 함수에서도 값 변경 가능
mutable -> 변이 가능한이라고 보면 됨

#include <iostream>

class A 
{
  mutable int data_;

 public:
  A(int data) : data_(data) {}
  void DoSomething(int x) const 
  {
    data_ = x;  // 컴파일 에러 발생하지 않음
  }

  void PrintData() const { std::cout << "data: " << data_ << std::endl; }
};

int main() 
{
  A a(10);
  a.DoSomething(3);
  a.PrintData();
}

mutable이 필요한 예

유저의 정보를 확인해서 캐쉬에 데이터를 넣어야 할 때
(유저의 정보는 읽기만 가능해야 하고, 캐쉬는 업데이트가 가능해야 함)

class Server 
{
  // .... (생략) ....

  mutable 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); // mutable 사용하지 않으면 캐쉬 업데이트 불가
    }

    // 3. 리턴된 정보로 User 객체 생성
    return User(user_data);
  }
};
post-custom-banner

0개의 댓글