2011-08-08 5 views
7

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

#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; 
} 
+3

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

+3

+1 для обеспечения минимальной полной программы выборки. Для получения дополнительной информации см. Http://sscce.org/. –

ответ

12

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

§ 7.1.6.1 (4) from N3242:

Except that any class member declared mutable can be modified, any attempt to modify a const object during its lifetime results in undefined behavior.

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

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

4

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

2

У меня нет решения проблемы. Я просто могу сказать, не используйте const_cast, если только намерение не вызывать функцию-член-константу из функции не-const-члена, а const_cast - результат const (чтобы сделать его изменчивым результатом для функции не-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

Проблема эта линия:

static int const v; 

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

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

2

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

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

6

5.2.11.7:

Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member resulting from a const_cast that casts away a const-qualifier) may produce undefined behavior (7.1.5.1)

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

+1

Это ненормативное примечание (т. Е. Оно только информационное). Нормативный текст приведен в §7.1.5.1. –

+0

В проекте содержится пункт 7.1.6.1. См. Мой ответ. – pmr

+1

@pmr: Правильно, потому что спецификация C++ 0x добавляет предложение, определяющее 'constexpr'. –

2

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

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