Const_cast безопасно?

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

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

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

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

7 ответов

Решение

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

Я могу вспомнить две ситуации, когда 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];
    }
};

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

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

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

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

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

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

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

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

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

#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

Другие вопросы по тегам