const_cast статического константного члена - PullRequest
8 голосов
/ 08 августа 2011

Следующий код хорошо компилируется как с GCC (4.2-4.6), так и с Clang (2.1), но когда я запускаю исполняемый файл, он выдает «Ошибка шины: 10».Я не понимаю причину.

#include <iostream>

struct A
{
  static int const v;
  A() { ++*const_cast<int *>(&A::v); }
};

int const A::v = 0;

int main(int argc, char * argv[])
{
  A a, b, c;
  std::cout << a.v << std::endl;

  return 0;
}

Ответы [ 7 ]

12 голосов
/ 08 августа 2011

Я думаю, что соответствующая цитата:

§ 7.1.6.1 (4) из N3242:

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

Примеры иллюстрируют точку с использованием const_cast.Как отметил Джеймс: цитата может быть найдена в §7.1.5 в стандарте C ++ 03.

Небольшое уточнение: это правило языка позволяет компилятору использовать постоянную память (если она доступна)на целевой архитектуре), когда что-то объявлено const.Без этого правила const -ness всегда можно было бы отбросить, не опасаясь каких-либо последствий, и его использование было бы лишь вопросом дисциплины разработчика.Таким образом, вы можете, по крайней мере, сказать людям, что они вызывают UB, что обычно является хорошим сдерживающим фактором.Сам по себе const_cast не имеет большого значения, поскольку не имеет значения, как вы обманываете компилятор, позволяя вам манипулировать объектом const.

6 голосов
/ 08 августа 2011

5.2.11.7:

В зависимости от типа объекта операция записи через указатель, lvalue или указатель на элемент данных, полученный в результате const_cast, который отбрасывает квалификатор const), можетпроизвести неопределенное поведение (7.1.5.1)

В вашем случае вы пытаетесь изменить данные, которые находятся в сегменте только для чтения.

4 голосов
/ 08 августа 2011

Поскольку вам не разрешено изменять переменные, объявленные как const.

2 голосов
/ 08 августа 2011

В принципе, если переменная объявлена ​​const, компилятору разрешено выдавать результаты только для чтения в память. Получение указателя / ссылки на объект const с последующим использованием const_cast для удаления const может привести к неопределенному поведению.

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

2 голосов
/ 08 августа 2011

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

Все, что const_cast<T> делает, это удаляет постоянство переменной с точки зрения компилятора. Это позволяет компилятору выдавать код для записи в переменную. Но во время выполнения, если компилятор / компоновщик поместил переменную в постоянную память, аппаратное обеспечение остановит запись в ней независимо от того, как вы ее приведете.

2 голосов
/ 08 августа 2011

У меня нет решения для реальной проблемы.Я просто могу сказать, что не используйте const_cast, если только вы не собираетесь вызывать функцию-член const из неконстантной функции-члена и "const_cast" - результат const (чтобы сделать его непостоянным результатом для неконстантной функции-члена).

Но у меня есть предложение по улучшению вашего дизайна:

class A
{
private:
  static int v;
public:
  A() { ++v; }
  static int get_v() { return v; }
};

int A::v = 0;

int main(int argc, char * argv[])
{
  A a, b, c;
  std::cout << a.get_v() << std::endl;

  return 0;
}
1 голос
/ 08 августа 2011

Проблема в этой строке:

static int const v;

Поскольку вы объявили его const, const_cast вызывает неопределенное поведение - в вашем случае вам повезло с ошибкой шины (это ошибка сегментации на моемsystem).

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

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