language_const_cast

language_const_cast (const_cast 캐스팅)

서로 다른 cv-한정(cv-qualification)을 가진 타입 사이를 변환해요. constvolatile 한정을 추가하거나 제거할 때 쓰는 캐스트 연산자예요.

출처: cppreference

본문

문법

const_cast< target-type >( expression )

target-type 타입의 값을 돌려줘요.

설명

const_cast로 할 수 있는 변환은 다음 뿐이에요.

    1. 두 유사 객체 포인터 또는 데이터 멤버 포인터 타입 T1T2에 대해, T1T2가 cv-한정에서만 다르다면(형식적으로 양 타입의 qualification-decomposition에서 모든 P1_iP2_i와 같다면) T1 타입의 prvalue를 T2로 변환할 수 있어요.
    • 표현식이 널 포인터 값이면 결과도 널 포인터 값이에요.
    • 표현식이 널 멤버 포인터 값이면 결과도 널 멤버 포인터 값이에요.
    • 표현식이 객체를 가리키면 결과는 같은 객체를 가리켜요.
    • 표현식이 객체의 끝을 넘어 가리키면 결과도 같은 객체의 끝을 넘어 가리켜요.
    • 표현식이 데이터 멤버를 가리키면 결과는 같은 데이터 멤버를 가리켜요.
    • 표현식이 prvalue여도 임시 객체 구체화(temporary materialization)는 수행되지 않아요. (C++17)
    1. 두 객체 타입 T1, T2에 대해, T1에 대한 포인터를 const_cast<T2*>로 "T2에 대한 포인터" 타입으로 명시적 변환할 수 있다면 다음 변환도 할 수 있어요.
    • T1 타입의 lvalue를 const_cast<T2&>T2 타입의 lvalue로 명시적 변환할 수 있어요.
    • T1 타입의 glvalue를 const_cast<T2&&>T2 타입의 xvalue로 명시적 변환할 수 있어요. (C++11)
    • T1이 클래스나 배열 타입이면, T1 타입의 prvalue를 const_cast<T2&&>T2 타입의 xvalue로 명시적 변환할 수 있어요. (C++11)

결과 참조는 원본 객체를 가리켜요. (C++17 이전) 표현식이 glvalue면 결과 참조는 원본 객체를, 그렇지 않으면 구체화된 임시 객체를 가리켜요. (C++17 이후)

모든 캐스트 표현식과 마찬가지로 결과는 다음 중 하나예요.

  • target-type이 lvalue 참조 타입이거나 함수 타입에 대한 rvalue 참조이면 lvalue (C++11)
  • target-type이 객체 타입에 대한 rvalue 참조이면 xvalue (C++11)
  • 그 외에는 prvalue

const 제거 (Casting away constness)

서로 다른 두 타입 T1, T2에 대해 T1에서 T2로의 변환은, T2의 qualification-decomposition이 "cv2_0 P2_0 cv2_1 P2_1 ... cv2_n−1 P2_n−1 cv2_n U2" 형태인데 T1을 "cv2_0 P1_0 ... cv2_n U1"(같은 cv 구성 요소, 다른 P·U 구성 요소)로 바꾸는 qualification 변환이 없을 때 const를 제거한다고 해요.

T1*의 prvalue에서 T2* 타입으로의 캐스트가 const를 제거한다면, T1 타입의 표현식에서 T2에 대한 참조로의 캐스트도 const를 제거해요. const를 제거하는 데는 const_cast만 쓸 수 있어요. "const 제거"는 "volatile 제거"를 암시해요. qualification 변환은 volatile도 제거할 수 없기 때문이에요.

주의 (Notes)

함수 포인터와 멤버 함수 포인터는 const_cast의 대상이 아니에요.

const_cast는 실제로 const 객체를 가리키는 비-const 타입 참조·포인터를 만들 수 있게 해요. 비-const 접근 경로로 const 객체를 수정하거나, 비-volatile glvalue로 volatile 객체를 참조하면 미정의 동작이에요.

키워드

const_cast

예제

#include <iostream>

struct type
{
    int i;
    type(): i(3) {}

    void f(int v) const
    {
        // this->i = v;                 // 컴파일 오류: this 는 const 에 대한 포인터
        const_cast<type*>(this)->i = v; // 타입 객체가 const 가 아니면 OK
    }
};

int main()
{
    int i = 3;                 // i 는 const 로 선언되지 않음
    const int& rci = i;
    const_cast<int&>(rci) = 4; // OK: i 를 수정
    std::cout << "i = " << i << '\n';

    type t; // 만약 const type t 였다면 t.f(4) 는 UB
    t.f(4);
    std::cout << "type::i = " << t.i << '\n';

    const int j = 3; // j 는 const 로 선언됨
    [[maybe_unused]]
    int* pj = const_cast<int*>(&j);
    // *pj = 4;      // 미정의 동작

    [[maybe_unused]]
    void (type::* pmf)(int) const = &type::f; // 멤버 함수 포인터
    // const_cast<void(type::*)(int)>(pmf);   // 컴파일 오류: const_cast 는
                                              // 함수 포인터에 동작하지 않음
}

출력:

i = 4
type::i = 4

더 알아보기 (Learn more)

cppreference