Const_cast безопасно? - PullRequest
       47

Const_cast безопасно?

87 голосов
/ 11 декабря 2008

Я не могу найти много информации о const_cast. Единственная информация, которую я смог найти (о переполнении стека):

const_cast<>() используется для добавления / удаления константы (ness) (или изменчивости) переменной.

Это заставляет меня нервничать. Может ли использование const_cast вызвать неожиданное поведение? Если так, то что?

В качестве альтернативы, когда можно использовать const_cast?

Ответы [ 7 ]

86 голосов
/ 11 декабря 2008

const_cast безопасен, только если вы приводите переменную, которая изначально не была const. Например, если у вас есть функция, которая принимает параметр const char *, и вы передаете изменяемую переменную char *, можно const_cast вернуть этот параметр обратно в char * и изменить его. Однако, если исходная переменная действительно была const, то использование const_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
34 голосов
/ 11 декабря 2008

Я могу вспомнить две ситуации, когда const_cast безопасен и полезен (могут быть и другие допустимые случаи).

Один из них - когда у вас есть экземпляр const, ссылка или указатель, и вы хотите передать указатель или ссылку на API, который не является const-правильным, но что вы УВЕРЕНЫ, не будет изменять объект. Вы можете 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()));
}

Другой вариант, если вы используете более старый компилятор, который не реализует 'mutable', и вы хотите создать класс, который является логически постоянным, но не побитовым const. Вы можете const_cast 'this' внутри метода const и изменять членов вашего класса.

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];
    }
};
22 голосов
/ 11 декабря 2008

Мне трудно поверить, что это только информация о , которую можно найти о const_cast. Цитируя из второго Google, хит :

Если вы отбросите постоянство объект, который был явно объявлен как const, и попытка изменить его, результаты не определены.

Однако, если вы выбросите постоянство объекта, который не имеет был явно объявлен как const, вы можете изменить его безопасно.

10 голосов
/ 11 декабря 2008

Что говорит Адам. Еще один пример, в котором может помочь 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 должно быть неконстантным ( в противном случае неконстантная версия getT не могла бы быть вызвана). Это может быть очень полезно, если вы получили большое тело функции и хотите избежать избыточного кода.

9 голосов
/ 11 декабря 2008

Короткий ответ - нет, это не безопасно.

Длинный ответ таков: если вы знаете достаточно, чтобы использовать его, тогда он должен быть безопасным.

Когда вы читаете, то, по сути, говорите: «Я знаю то, чего не знает компилятор». В случае с const_cast вы говорите: «Несмотря на то, что этот метод использует неконстантную ссылку или указатель, я знаю, что он не изменит параметр, который я передаю».

Так что, если вы действительно знаете, что, как вы утверждаете, знаете при использовании актерского состава, то это нормально - использовать.

5 голосов
/ 11 декабря 2008

Вы разрушаете любой шанс безопасности потока, если начинаете изменять вещи, которые компилятор считал постоянными.

0 голосов
/ 19 июля 2012
#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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...