static_cast
함수는 C 스타일 또는 간단한 함수 스타일 캐스팅보다 선호되어야한다고 들었습니다 . 이것이 사실입니까? 왜?
static_cast
함수는 C 스타일 또는 간단한 함수 스타일 캐스팅보다 선호되어야한다고 들었습니다 . 이것이 사실입니까? 왜?
답변:
주된 이유는 고전적인 C 캐스트는 우리가 부르는 사이에 구분하지 않습니다이다 static_cast<>()
, reinterpret_cast<>()
, const_cast<>()
,와 dynamic_cast<>()
. 이 네 가지가 완전히 다릅니다.
A static_cast<>()
는 일반적으로 안전합니다. 언어의 유효한 변환 또는 가능하게하는 적절한 생성자가 있습니다. 약간 위험한 유일한 시간은 상속 된 클래스로 캐스트 할 때입니다. 객체가 실제로 언어의 외부 (예 : 객체의 플래그)와 같은 객체라고 주장하는 자손인지 확인해야합니다. A dynamic_cast<>()
는 결과가 확인되거나 (포인터) 가능한 예외가 고려되는 한 (참조) 안전합니다.
반면에 reinterpret_cast<>()
(또는 a const_cast<>()
)는 항상 위험합니다. 당신은 컴파일러에게 다음과 같이 말합니다 : "믿어주세요 : 이것이 마치 마치 변하지 않는 것처럼 foo
보이지만 그것이 그렇다는 것을 알고 있습니다."
첫 번째 문제는 크고 분산 된 코드를 보지 않고 모든 규칙을 알지 못하면 C 스타일 캐스트에서 어떤 것이 발생하는지 알 수 없다는 것입니다.
이것을 가정 해 봅시다 :
class CDerivedClass : public CMyBase {...};
class CMyOtherStuff {...} ;
CMyBase *pSomething; // filled somewhere
이제이 두 방법은 같은 방식으로 컴파일됩니다.
CDerivedClass *pMyObject;
pMyObject = static_cast<CDerivedClass*>(pSomething); // Safe; as long as we checked
pMyObject = (CDerivedClass*)(pSomething); // Same as static_cast<>
// Safe; as long as we checked
// but harder to read
그러나 거의 동일한 코드를 보자.
CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert
pOther = (CMyOtherStuff*)(pSomething); // No compiler error.
// Same as reinterpret_cast<>
// and it's wrong!!!
보시다시피, 관련된 모든 수업에 대해 많이 몰라도 두 상황을 쉽게 구별 할 수있는 방법은 없습니다.
두 번째 문제는 C 스타일 캐스트를 찾기가 너무 어렵다는 것입니다. 복잡한 표현에서는 C 스타일 캐스트를보기가 매우 어려울 수 있습니다. 완전한 C ++ 컴파일러 프론트 엔드없이 C 스타일 캐스트 (예 : 검색 도구)를 찾아야하는 자동화 된 도구를 작성하는 것은 사실상 불가능합니다. 한편, "static_cast <"또는 "reinterpret_cast <"를 쉽게 검색 할 수 있습니다.
pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
// No compiler error.
// but the presence of a reinterpret_cast<> is
// like a Siren with Red Flashing Lights in your code.
// The mere typing of it should cause you to feel VERY uncomfortable.
즉, C 스타일 캐스트가 더 위험 할뿐만 아니라 모두 올바른지 확인하기가 훨씬 어렵습니다.
static_cast
상속 계층 구조를 캐스트하는 데 사용하지 말고을 사용해야 합니다 dynamic_cast
. null 포인터 또는 유효한 포인터를 반환합니다.
static_cast
그 상황에서 사용할주의 사항을 지적했다고 생각 합니다. dynamic_cast
더 안전 할 수도 있지만 항상 최선의 방법은 아닙니다. 때로는 포인터가 주어진 하위 유형을 가리키는 것으로 컴파일러에 대해 불투명하고 a 가 더 빠르다 는 것을 알고static_cast
있습니다. 적어도 일부 환경 dynamic_cast
에서는 선택적 컴파일러 지원 및 런타임 비용 (RTTI 사용)이 필요하며, 몇 가지 점검만으로 직접 사용하지 않을 수도 있습니다. C ++의 RTTI는이 문제를 해결할 수있는 유일한 솔루션입니다.
static_cast
입니다. C에 해당하는 reinterpret_cast
것은 *(destination_type *)&
즉, 객체의 주소를 가져 와서 해당 주소를 다른 유형에 대한 포인터로 캐스트 한 다음 역 참조하는 것입니다. C는이 구조의 동작을 정의하는 문자 유형 또는 특정 구조체 타입의 경우를 제외하고는 일반적으로 정의되지 않은 동작에 C. 결과
int
(및 int
단독)의 경우 static_cast<int>
vs (int)
를 유일한 장점으로 사용하는 이유 는 클래스 변수와 포인터에있는 것 같습니다. 이에 대해 자세히 설명하십시오.
int
dynamic_cast
는 적용되지 않지만 다른 모든 이유가 있습니다. 예를 들어 :하자 말은 v
로 선언 된 함수 매개 변수는 float
다음 (int)v
이다 static_cast<int>(v)
. 당신의 매개 변수를 변경한다면 float*
, (int)v
조용히하게 reinterpret_cast<int>(v)
하면서 static_cast<int>(v)
불법 올바르게 컴파일러에 의해 잡힐 것입니다.
실용적인 팁 : 프로젝트를 정리하려는 경우 소스 코드에서 static_cast 키워드를 쉽게 검색 할 수 있습니다.
int
매개 변수를 사용한 함수 선언 .
한마디로 :
static_cast<>()
컴파일 시간 검사 기능을 제공하지만 C 스타일 캐스트는 그렇지 않습니다.static_cast<>()
C ++ 소스 코드의 어느 곳에서나 쉽게 발견 할 수 있습니다. 반면에 C_Style 캐스트는 찾기가 더 어렵습니다.- C ++ 캐스트를 사용하면 의도가 훨씬 더 잘 전달됩니다.
더 많은 설명 :
정적 캐스트는 호환 가능한 유형 간에 변환을 수행합니다 . C 스타일 캐스트와 비슷하지만 더 제한적입니다. 예를 들어 C 스타일 캐스트는 정수 포인터가 문자를 가리 키도록 허용합니다.
char c = 10; // 1 byte int *p = (int*)&c; // 4 bytes
이로 인해 1 바이트의 할당 된 메모리를 가리키는 4 바이트 포인터가 생성되므로이 포인터에 쓰면 런타임 오류가 발생하거나 일부 인접한 메모리를 덮어 씁니다.
*p = 5; // run-time error: stack corruption
C 스타일 캐스트와 달리 정적 캐스트는 컴파일러가 포인터 및 포인트 데이터 유형이 호환되는지 확인하여 프로그래머가 컴파일 중에이 잘못된 포인터 할당을 잡을 수있게합니다.
int *q = static_cast<int*>(&c); // compile-time error
자세한 내용 :
static_cast <> 및 C 스타일 캐스팅
과 일반 캐스트 대 static_cast 대 dynamic_cast 의 차이점은 무엇입니까?
static_cast<>()
더 읽기 쉽다는 것에 동의하지 않습니다 . 내 말은, 때로는 그렇습니다. 그러나 대부분의 경우, 특히 기본 정수 유형의 경우에는 끔찍하고 불필요하게 장황합니다. 예를 들면 다음과 같습니다. 32 비트 워드의 바이트를 바꾸는 함수입니다. static_cast<uint##>()
캐스트를 사용하여 읽는 것은 거의 불가능 하지만 (uint##)
캐스트를 사용하여 이해하기는 쉽습니다 . 코드 그림 : imgur.com/NoHbGve
always
. (그러나 대부분의 경우 예) c 스타일 캐스트가 더 읽기 쉬운 경우가 있습니다. 그것이 c 스타일 캐스팅이 여전히 살아 있고 c ++ imho에서 발로 드는 이유 중 하나입니다. :) 그건 그렇고 아주 좋은 예였습니다
(uint32_t)(uint8_t)
)을 사용하여 가장 낮은 바이트 이외의 바이트가 재설정되도록합니다. 이를 위해 비트와 ( 0xFF &
)가 있습니다. 캐스트 사용은 의도를 혼란스럽게 만듭니다.
C 스타일 캐스트를 사용할 때 다른 일이 발생하기 때문에 wither static_cast 또는 C 스타일 캐스팅을 사용하는 것보다 문제가 더 큽니다. C ++ 캐스팅 연산자는 이러한 작업을보다 명확하게하기위한 것입니다.
표면에서 static_cast와 C 스타일 캐스트는 같은 것으로 보입니다 (예 : 하나의 값을 다른 값으로 캐스트 할 때).
int i;
double d = (double)i; //C-style cast
double d2 = static_cast<double>( i ); //C++ cast
둘 다 정수 값을 두 배로 캐스트합니다. 그러나 포인터로 작업 할 때 상황이 더 복잡해집니다. 몇 가지 예 :
class A {};
class B : public A {};
A* a = new B;
B* b = (B*)a; //(1) what is this supposed to do?
char* c = (char*)new int( 5 ); //(2) that weird?
char* c1 = static_cast<char*>( new int( 5 ) ); //(3) compile time error
이 예제에서 (1) A가 가리키는 객체가 실제로 B의 인스턴스이기 때문에 OK 일 수 있습니다. 그러나 코드에서 그 시점에서 실제로 가리키는 것이 무엇인지 모른다면 어떻게 될까요? (2) 아마도 완벽하게 합법적 일 수 있습니다 (정수의 1 바이트 만보 고 싶을 수도 있음). (3)과 같이 오류가 좋을 수도 있습니다. C ++ 캐스팅 연산자는 가능한 경우 컴파일 타임 또는 런타임 오류를 제공하여 이러한 문제를 코드에 노출 시키려고합니다.
따라서 엄격한 "값 캐스팅"의 경우 static_cast를 사용할 수 있습니다. 포인터의 런타임 다형성 캐스팅을 원한다면 dynamic_cast를 사용하십시오. 실제로 유형을 잊고 싶다면 reintrepret_cast를 사용할 수 있습니다. 그리고 const를 창 밖으로 던지기 위해 const_cast가 있습니다.
그들은 당신이하고있는 일을 알고있는 것처럼 보이도록 코드를보다 명확하게 만듭니다.
static_cast
실수로 const_cast
또는 할 수 없다는 것을 의미합니다 reinterpret_cast
.
효과적인 C ++ 소개 참조
얼마나 많은 유형 안전을 부과하고 있는지에 관한 것입니다.
쓸 때 (bar) foo
( reinterpret_cast<bar> foo
형식 변환 연산자를 제공하지 않은 경우 와 동일 ) 컴파일러는 형식 안전을 무시하고 지시대로 지시합니다.
작성할 때 static_cast<bar> foo
컴파일러가 최소한 형식 변환이 의미가 있는지 확인하고 정수 형식의 경우 변환 코드를 삽입하도록 요청합니다.
편집 2014-02-26
나는 5 년 전에이 답변을 썼는데, 틀렸다. (의견을 참조하십시오.) 그러나 여전히 공세를 얻습니다!
static_cast<bar>(foo)
괄호 안에 있습니다. 동일합니다 reinterpret_cast<bar>(foo)
.
C 스타일 캐스트는 코드 블록에서 놓치기 쉽습니다. C ++ 스타일 캐스트는 더 나은 연습 일뿐만 아니라; 그들은 훨씬 더 큰 유연성을 제공합니다.
reinterpret_cast를 사용하면 포인터 유형 변환에 정수를 사용할 수 있지만 잘못 사용하면 안전하지 않을 수 있습니다.
static_cast는 숫자 형에 대해 열거 형에서 정수로 또는 정수에서 부동 소수점으로 또는 유형이 확실한 데이터 형식으로 변환하는 기능을 제공합니다. 런타임 검사는 수행하지 않습니다.
반면에 dynamic_cast는 모호한 할당 또는 변환을 표시하는 이러한 검사를 수행합니다. 포인터와 참조에서만 작동하며 오버 헤드가 발생합니다.
다른 몇 가지가 있지만 이것들은 당신이 보게 될 주요한 것입니다.
클래스에 대한 포인터 조작과 함께 static_cast를 사용하여 클래스에 명시 적으로 정의 된 변환을 수행하고 기본 유형 간의 표준 변환을 수행 할 수 있습니다.
double d = 3.14159265;
int i = static_cast<int>(d);
static_cast<int>(d)
,하지만 때 (int)d
훨씬 더 간결하고 읽기? (객체 포인터가 아닌 기본 유형의 경우를 의미합니다.)
(int)d
할 때 int{d}
훨씬 더 읽을? 생성자 또는 함수와 같은 경우 ()
구문은 복잡한 식에서 괄호의 악몽 같은 미로로 전환하기에는 그리 빠르지 않습니다. 이 경우에는 int i{d}
대신에 사용 int i = (int)d
됩니다. 훨씬 더 나은 IMO. 즉, 표현식에서 임시가 필요할 때 static_cast
생성자를 사용하지 않았으며 결코 사용하지 않았습니다. 나는 (C)casts
서둘러 디버그를 쓸 때만 사용합니다 cout
...