Является ли const_cast безопасным?
Я не могу найти много информации о const_cast
. Единственная информация, которую я мог найти (в Stack Overflow), это:
const_cast<>()
используется для добавления/удаления константы (или изменчивости) переменной.
Это заставляет меня нервничать. Может ли использование const_cast
вызвать неожиданное поведение? Если да, то что?
В качестве альтернативы, когда можно использовать const_cast
?
Ответы
Ответ 1
const_cast
является безопасным, только если вы производите переменную, которая изначально была не const
. Например, если у вас есть функция, которая принимает параметр const char *
, и вы проходите модификатор char *
, он сохраняет const_cast
этот параметр обратно на char *
и модифицирует его. Однако, если исходная переменная была фактически const
, то использование const_cast
приведет к поведению undefined.
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
Ответ 2
Я могу думать о двух ситуациях, когда 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()));
}
Другой - если вы используете более старый компилятор, который не реализует "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];
}
};
Ответ 3
Мне трудно поверить, что это единственная информация, которую вы могли бы найти о const_cast. Цитата из второй Google ударил:
Если вы отбросили объект, который был явно объявлен как const, и попытаться измените его, результаты undefined.
Однако, если вы отбросили constness объекта, который не был явно объявлен как const, вы может безопасно его модифицировать.
Ответ 4
Что говорит Адам. Другой пример, в котором может быть полезен 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
). Это может быть очень полезно, если вы получили большое тело функции и хотите избежать избыточного кода.
Ответ 5
Короткий ответ - нет, это не безопасно.
Долгий ответ: если вы знаете достаточно, чтобы использовать его, тогда он должен быть безопасным.
Когда вы кастинг, вы, по сути, говорите: "Я знаю, что компилятор не знает". В случае const_cast вы говорите: "Даже если этот метод принимает неконстантную ссылку или указатель, я знаю, что он не изменит параметр, который я передаю".
Итак, если вы действительно знаете, о чем вы заявляете, чтобы знать, используя приведение, то это прекрасно, чтобы использовать его.
Ответ 6
Вы уничтожаете любой шанс на безопасность потоков, если вы начнете изменять вещи, которые, по мнению компилятора, были const.
Ответ 7
#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