치춘짱베리굿나이스

[Rank 5] ft_containers - explicit 키워드 본문

42/42s Cursus

[Rank 5] ft_containers - explicit 키워드

치춘 2023. 1. 13. 15:38

explicit

서론

ft_containers의 오랜 친구 cplusplus.comcppreference.com 을 보다 보면? 생성자 등등에 explicit 이라는 키워드를 자주 볼 수 있다

나는 C++ 이 주 언어가 아니라서 이게 어디다 쓰는 키워드인지 전혀 몰랐는데!! 과제를 하겠다고 무작정 따라 칠 수만은 없는 노릇이다

따라서 잊어버리기 전에 적어두려고 한다 (매우 짧음 주의)

뭐하는 친구인가

explicit은 ‘명백한, 분명한’ 이라는 의미의 영단어이다

무엇을 분명하게 만들어 주는 키워드라는 것을 짐작할 수 있다

C++ 에서의 묵시적 형변환

[Rank 4] CPP 06

CPP Module 06에서 공부했던 묵시적 형변환에 관해서 잠깐 보고 가자

 

그렇다고 한다

 

요약하자면 묵시적 형변환이란? 이런 타입으로 형변환을 하겠다~~ 라고 명시하지 않았는데 컴파일러가 코드를 읽고 음 이렇게 변환하면 되겠군 하고 임의로 판단하여 (묵시적으로) 형변환을 하는 경우이다

explicit이 없을 때의 예시

class IntInt {
    public:
        int _value;
        IntInt() {}
        IntInt(int value): _value(value) {}
};

IntInt 클래스를 만들었다

IntInt 클래스는 생성자에서 int형 값 value를 받아 멤버 변수 _value를 초기화한다

 

void printValue(IntInt i) {
    std::cout << "Value is [" << i._value << "]\n";
}

printValue 함수는 인자로 IntInt 클래스의 인스턴스를 받으며, 멤버 변수 _value를 출력한다

 

int main(void) {
    IntInt i = IntInt(10);
    printValue(i); // 10
}

이 경우에는 iIntInt 클래스의 인스턴스이기 때문에 문제없이 printValue 함수가 작동할 것이다

누가 봐도 정상적인 동작을 하는 코드이다

 

int main(void) {
    int i = 100;
    printValue(i);
}

하지만 이 경우에는? iint 자료형의 변수이며, IntInt 클래스와 전혀 관계가 없다

따라서 i._value 를 찾지 못해 코드가 오류를 뿜어내야 정상이다

 

근데 정상 작동이 된다 (헐)

 

왜 오류가 나지 않는 것일까? 생성자를 조금 개조해서 동작을 보도록 하자

 

class    IntInt {
    public:
        int    _value;
        IntInt(): _value(0) {
            std::cout << "Default constructor called\n";
        }
        IntInt(int value): _value(value) {
            std::cout << "Initialization constructor called (value: [" << value << "])\n";
        }
};

생성자에 출력문을 추가했다

이제 생성자가 호출될 때마다 문구가 출력될 것이므로, 언제 생성자가 호출되었는지 알 수 있다

 

같은 main문을 돌렸을 때, 분명 생성자를 호출하는 부분이 없었음에도 불구하고 생성자가 호출되었다!

printValue(i) 호출 시에 컴파일러가 임의로 IntInt 인스턴스를 생성했다는 것을 추측할 수 있다

이 경우 동작 순서는 다음과 같다

  1. printValue(i)를 호출한다 → 이때 iint형이다
  2. printValue의 인자는 IntInt 인스턴스여야 하는데 int 값이 들어왔다?
  3. 컴파일러는 intIntInt 간의 형변환을 시도한다
  4. 컴파일러는 IntInt 클래스의 생성자 중, int 값을 인자로 받아 인스턴스를 생성하는 생성자를 찾는다
  5. int i = 100을 이용하여 IntInt 클래스의 생성자를 호출한다 → IntInt 인스턴스가 생성되었다
  6. 생성된 인스턴스로 printValue 함수를 동작시킨다 (묵시적 형변환 완료)

결론적으로, 컴파일러가 임의로 적절한 생성자를 호출하여 함수를 동작시켰기 때문에 오류가 나지 않았다는 것이다

이러한 묵시적 형변환이 편할 때도 많지만, 가끔은 컴파일러가 멋대로 타입을 바꿔버리는 것이 오히려 기상천외한 버그를 낳을 수도 있다

그런 경우를 대비하여 “너 이거는 묵시적 형변환으로 동작시키면 안돼” 라고 컴파일러에게 알려주는 키워드가 explicit 키워드이다

explicit을 사용한 예시

class IntInt {
    public:
        int _value;
        IntInt() {}
        explicit IntInt(int value): _value(value) {}
};

위의 IntInt 클래스에서 생성자 선언 앞에 explicit 키워드를 추가하고, 나머지는 똑같이 작성한 뒤 컴파일해 보자

 

드디어 오류가 났다

printValue의 인자로 int가 들어왔는데, 그에 맞는 함수가 없다는 내용의 오류이다

 

당연하다! int에서 IntInt로의 형변환이 불가능해졌기 때문이다

explicit 키워드를 만난 컴파일러는 “ㅇㅇ 묵시적 형변환 안할게” 라며 int i = 100을 형변환하지 않기 때문에, printValue를 호출할 수 없어 오류가 발생하였다

 

이처럼 explicit 키워드는 컴파일러가 임의로 행하는 묵시적 형변환을 막기 위해 사용된다

강제로 형변환을 했을 때 오류가 발생할 수 있는 경우를 막아주는 키워드인 것이다

Comments