2008-12-10 6 views
81

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

const_cast<>() используется для добавления/удаления сопзЬ (Ness) (или летучего-Несс) переменной.

Это заставляет меня нервничать. Не удалось ли вызвать const_cast? Если да, то?

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

+1

Верхний ответ выходит что-то, что может быть ужасно очевидным, но стоит заявив: Это только становится небезопасным _If вы пытаетесь изменить первоначально `const` object_ через де-`const` -ed reference/pointer. Если вместо этого вы просто `const_cast`, чтобы работать с плохой (или, в моем случае, лениво) spec'd API, который принимает только ссылку, отличную от `const`, но будет использоваться только в` const` методах ... никаких проблем. – 2015-12-22 01:39:30

ответ

89

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 
+8

Это неправда. Стандарт C++. `§7.1. 5.1/4 говорит За исключением того, что любой член класса, объявленный mutable (7.1.1), может быть изменен, любая попытка изменить объект const во время его жизни (3.8) приводит к неопределенному поведению` ** Любая попытка **! Нет слов об исходной переменной. – 2010-11-08 15:12:56

+18

@Alexey: Исходная переменная относится к тому, на что указывает или упоминается. Вы можете взять константную ссылку на объект, не являющийся константой, и, следовательно, отличить его от записи, доступной для записи, является корректным поведением, поскольку упомянутый объект фактически не является константой. – Puppy 2010-11-09 16:53:29

+0

@DeadMG: `Вы можете взять ссылку на const для неконстантного объекта`. Это все. После этого у вас есть объект const, а не не const const. Более того, есть случаи, когда разрешено создавать константную копию исходного неконстантного объекта. Например, для аргумента функции. – 2010-11-12 10:23:28

22

Я считаю, что трудно поверить, что это информация только можно найти о const_cast. Цитируя second Google hit:

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

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

5

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

10

Что говорит Адам. Другой пример, где 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; 
}; 

Сначала добавьте сопзЬ к типу this очков, то мы называем константные версии getT, а затем удалить сопзЬ из возвращаемого типа, который вступает в силу с t должен быть неконстантным (иначе нельзя было бы назвать неконстантную версию getT). Это может быть очень полезно, если вы получили большое тело функции и хотите избежать избыточного кода.

32

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

Один из них, когда у вас есть экземпляр const, ссылка или указатель, и вы хотите передать указатель или ссылку на API, который не является const-правильным, но вы 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_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]; 
    } 
}; 
7

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

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

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

Итак, если вы действительно знаете, о чем вы заявляете, чтобы узнать, используя приведение, то это нормально использовать.

-1
#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