const_cast는 안전한가요?


92

에 대한 정보를 많이 찾을 수 없습니다 const_cast. 내가 찾을 수있는 유일한 정보 (Stack Overflow에서)는 다음과 같습니다.

const_cast<>()/ 변수 제거 CONST (호) (휘발성 또는 호)를 추가하는 데 사용된다.

이것은 나를 긴장하게 만든다. const_cast예기치 않은 동작을 유발할 수 있습니까? 그렇다면 무엇입니까?

또는 언제 사용해도 괜찮 const_cast습니까?


4
최고 답변은 끔찍할 수 있지만 말할 가치가있는 것을 간과 합니다. 정의 된 참조 / 포인터 를 통해 원래 const객체수정하려고 시도하는 경우 에만 안전하지 않습니다const . 대신에, const_castconst참조 만 받아들이지 만 const메서드 에서만 사용되는 저조한 (또는 제 경우에는 게으른) 사양의 API를 해결하려는 경우 에만 문제가 없습니다.
underscore_d

1
@underscore_d :이를 다루는 질문 (및 답변)의보다 정확한 버전은 다음과 같습니다. 실제로 수정되지 않는 한 const로 정의 된 객체에서 const를 캐스트 할 수 있습니까?
Peter Cordes 2019

답변:


88

const_cast원래 non- 변수를 캐스팅하는 경우에만 안전합니다 const. 예를 들어 a의 매개 변수를받는 함수가 const char *있고 modifiable을 전달하는 경우 해당 매개 변수를 다시 a 로 수정하고 수정하는 것이 char *안전 합니다. 그러나 원래 변수가 실제로 이면를 사용 하면 정의되지 않은 동작이 발생합니다.const_castchar *constconst_cast

void func(const char *param, size_t sz, bool modify)
{
    if(modify)
        strncpy(const_cast<char *>(param), sz, "new string");
    printf("param: %s\n", param);
}

...

char buffer[16];
const char *unmodifiable = "string constant";
func(buffer, sizeof(buffer), true);  // OK
func(unmodifiable, strlen(unmodifiable), false); // OK
func(unmodifiable, strlen(unmodifiable), true);  // UNDEFINED BEHAVIOR

9
그것은 사실이 아닙니다. C ++ 표준. §7.1.​5.1/4 says Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior 모든 시도 ! 원래 변수에 대한 단어가 없습니다.
Alexey Malistov 2010

20
@Alexey : 원래 변수는 가리 키거나 참조하는 것에 관한 것입니다. const가 아닌 개체에 대한 const 참조를 사용할 수 있으므로 참조 된 개체가 실제로 const가 아니기 때문에 쓰기 가능한 참조로 캐스팅하는 것은 잘 정의 된 동작입니다.
Puppy

43
@Alexey Malistov : 아니요. "개체"는 메모리에서 차지하는 실제 저장소 영역을 나타냅니다 (§1.7). const가 아닌 객체에 대한 const 참조를 사용하면 객체가 const가되지 않습니다. CONST 만의 경우에 기준 파라미터 ( 되지 CONST 포인터 파라미터)를 자동 복사 (§5.2.2 / 5)를 만들 수 컴파일러이고; 여기서는 그렇지 않습니다.
Adam Rosenfield

8
"그러나 원래 변수가 실제로 const이면 const_cast를 사용하면 정의되지 않은 동작 이 발생합니다. " 이 문장은 거짓입니다.
궤도에서 가벼운 경주

7
그건 하지 사용할 UB const_cast제거하기 위해 const처음 선언에서 뭔가 const. 그러나 실제로 그 객체에 쓰기를 시도 하는 것은 UB입니다. 당신이 방금 읽은 한 당신은 const_cast괜찮고 그 자체로 UB를 일으키지 않습니다. 끔찍한 생각이지만 본질적으로 UB는 아닙니다.
Jesper Juhl

35

const_cast가 안전하고 유용한 두 가지 상황을 생각할 수 있습니다 (다른 유효한 경우가있을 수 있음).

하나는 const 인스턴스, 참조 또는 포인터가 있고 const- 올바르지 않은 API에 대한 포인터 또는 참조를 전달하려는 경우이지만 CERTAIN은 개체를 수정하지 않습니다. 포인터를 const_cast하고 API에 전달할 수 있으며 실제로 아무것도 변경되지 않을 것이라고 믿습니다. 예를 들면 :

void log(char* text);   // Won't change text -- just const-incorrect

void my_func(const std::string& message)
{
    log(const_cast<char*>(&message.c_str()));
}

다른 하나는 '변경 가능'을 구현하지 않는 이전 컴파일러를 사용하고 있고 논리적으로 const이지만 비트 const가 아닌 클래스를 만들려는 경우입니다. const 메서드 내에서 'this'를 const_cast하고 클래스 멤버를 수정할 수 있습니다.

class MyClass
{
    char cached_data[10000]; // should be mutable
    bool cache_dirty;        // should also be mutable

  public:

    char getData(int index) const
    {
        if (cache_dirty)
        {
          MyClass* thisptr = const_cast<MyClass*>(this);
          update_cache(thisptr->cached_data);
        }
        return cached_data[index];
    }
};

이것은 ...이 질문에 대답하지 않는 것 같습니다. 그는 물었다 const_cast그것의 유용한 응용 프로그램이없는 것을 정의되지 않은 동작이 발생할 수 있습니다
마이클 Mrozek

13
질문에서 : "또는 언제 const_cast를 사용해도 괜찮습니까?"
Fred Larson

"언제 정의되지 않은지"에서와 같이; 그는 그것이 유용 때의 예를 찾고 아니에요
마이클 Mrozek에게

우리는 질문의 글자 만 고수 할 수 있습니다. 이를 바탕으로의 예시적인 사용을 제시하는 const_cast것이 유효한 대답입니다. he질문 자체가 주제이므로 질문 에는 없습니다 .
eigenfield

24

이것이 const_cast에 대해 찾을 수 있는 유일한 정보 라는 것이 믿기지 않습니다. 두 번째 Google 히트 곡 에서 인용 :

const로 명시 적으로 선언 된 객체의 constness를 버리고 수정하려고하면 결과가 정의되지 않습니다.

그러나 명시 적으로 const로 선언되지 않은 객체의 constness를 캐스트하면 안전하게 수정할 수 있습니다.


Grrrreaat 대답, 이것을 이 대답 과 결합 하면 전체 그림을 얻을 수 있습니다.
bobobobo 2011

흠. 귀하의 답변의 두 번째 진술과 관련하여 처음에 const로 명시 적으로 선언되지 않은 객체에 대한 "const"ness가 어떻게 있는지 물어볼 수 있습니까?.
hAcKnRoCk

상수가 아닌 객체를 const, @Iam으로 만드는 방법에는 여러 가지가 있습니다. 예를 들어 객체를 const-reference 매개 변수로 전달합니다. 또는 상수에 대한 포인터에 할당하십시오. 또는 const_cast. 또는 그것에 const 메서드를 호출하십시오.
Rob Kennedy

12

아담이 말하는 것. const_cast가 도움이 될 수있는 또 다른 예 :

struct sample {
    T& getT() { 
        return const_cast<T&>(static_cast<const sample*>(this)->getT()); 
    }

    const T& getT() const { 
       /* possibly much code here */
       return t; 
    }

    T t;
};

우리는 먼저 타입에 const를 추가 this, 우리는의 CONST 버전 전화를 점 getT하고 우리는 이후 유효 반환 형식에서 const를 제거 t그렇지 않으면의 const가 아닌 버전 (const가 아닌 있어야합니다 getT수 없었다 호출되었습니다). 이것은 큰 함수 본문이 있고 중복 코드를 피하려는 경우 매우 유용 할 수 있습니다.


3
추가 constness : static_cast <const sample *> (this)에 정적 캐스트를 사용하고 싶습니다. const_cast를 읽을 때 코드가 잠재적으로 위험한 작업을 수행하고 있음을 의미하므로 가능한 경우 사용하지 않으려 고 노력합니다.
mfazekas

1
첫 번째는 static_cast이거나 implicit_cast (부스트) 일 수도 있습니다. 정적 캐스트를 사용하여 수정하겠습니다. 감사합니다
Johannes Schaub-litb

3
나는 const_cast또는 static_cast더 나은지 에 대해 앞뒤로 간다 . const_cast원하는 것만 할 수 있습니다 : cv 한정자를 변경합니다. static_cast의도하지 않은 다른 작업을 '조용히'수행 할 수 있습니다. 그러나 첫 번째 캐스트는 완전히 안전 static_cast하며 const_cast. 나는 이것이 const_cast당신의 의도를 더 잘 static_cast전달 하지만 당신의 행동의 안전을 더 잘 전달 하는 상황이라고 생각합니다 .
David Stone

10

짧은 대답은 '아니요'입니다. 안전하지 않습니다.

긴 대답은 당신이 그것을 사용할만큼 충분히 알고 있다면 안전해야한다는 것입니다.

캐스팅 할 때 본질적으로 말하는 것은 "컴파일러가 모르는 것을 알고 있습니다."입니다. const_cast의 경우 "이 메서드는 상수가 아닌 참조 또는 포인터를 가져 오더라도 전달하는 매개 변수를 변경하지 않을 것임을 알고 있습니다."라고 말합니다.

따라서 캐스트를 사용하면서 알고 있다고 주장하는 것을 실제로 알고 있다면 사용하는 것이 좋습니다.


5

컴파일러가 const라고 생각한 것을 수정하기 시작하면 스레드 안전성에서 기회를 파괴하는 것입니다.


1
뭐? 불변 (const) 객체가있는 경우 스레드간에 쉽게 공유 할 수 있습니다 . 코드 일부가 const-ness를 버리는 순간 모든 스레드 안전성을 잃게됩니다! 나는 왜 이것을 위해 다운 모드를 사용합니까? 한숨
Matt Cruikshank

8
Const는 확실히 코드를 스레드로부터 안전하게 만드는 데 유용한 도구이지만 보장 할 수는 없습니다 (컴파일 시간 상수의 경우 제외). 두 가지 예 : const 객체는 변경 가능한 멤버를 가질 수 있으며 객체에 대한 const 포인터를 갖는 것은 객체 자체가 변경 될 수 있는지 여부에 대해 아무것도 알려주지 않습니다.
James Hopkin

저는 이것이 좋은 대답이라고 생각합니다.. 단어를 사용할 때 컴파일러 최적화 프로그램의 신뢰와 보안에 대해 생각하지 않았기 때문 const입니다. const신뢰입니다. const_cast신뢰 :( 깨는
bobobobo

1
변경 가능 및 스레드 안전성 관련 : channel9.msdn.com/posts/…
MFH

-3
#include <iostream>
using namespace std;

void f(int* p) {
  cout << *p << endl;
}

int main(void) {
  const int a = 10;
  const int* b = &a;

  // Function f() expects int*, not const int*
  //   f(b);
  int* c = const_cast<int*>(b);
  f(c);

  // Lvalue is const
  //  *b = 20;

  // Undefined behavior
  //  *c = 30;

  int a1 = 40;
  const int* b1 = &a1;
  int* c1 = const_cast<int*>(b1);

  // Integer a1, the object referred to by c1, has
  // not been declared const
  *c1 = 50;

  return 0;
}

출처 : http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fkeyword_const_cast.htm


스팸 링크로 인한 반대 투표
eigenfield
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.