language_const_cast
language_const_cast (const_cast 캐스팅)
서로 다른 cv-한정(cv-qualification)을 가진 타입 사이를 변환해요. const나 volatile 한정을 추가하거나 제거할 때 쓰는 캐스트 연산자예요.
출처: cppreference
본문
문법
const_cast< target-type >( expression )
target-type 타입의 값을 돌려줘요.
설명
const_cast로 할 수 있는 변환은 다음 뿐이에요.
-
- 두 유사 객체 포인터 또는 데이터 멤버 포인터 타입
T1과T2에 대해,T1과T2가 cv-한정에서만 다르다면(형식적으로 양 타입의 qualification-decomposition에서 모든P1_i가P2_i와 같다면)T1타입의 prvalue를T2로 변환할 수 있어요.
- 표현식이 널 포인터 값이면 결과도 널 포인터 값이에요.
- 표현식이 널 멤버 포인터 값이면 결과도 널 멤버 포인터 값이에요.
- 표현식이 객체를 가리키면 결과는 같은 객체를 가리켜요.
- 표현식이 객체의 끝을 넘어 가리키면 결과도 같은 객체의 끝을 넘어 가리켜요.
- 표현식이 데이터 멤버를 가리키면 결과는 같은 데이터 멤버를 가리켜요.
- 표현식이 prvalue여도 임시 객체 구체화(temporary materialization)는 수행되지 않아요. (C++17)
- 두 유사 객체 포인터 또는 데이터 멤버 포인터 타입
-
- 두 객체 타입
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