Изменение self внутри метода const с помощью неконстантного указателя на себя
Вопрос
В следующем примере const
объект может изменять себя через const
метод, потому что в этом методе он обращается к самому себе через non-const
указатель.(та же программа на ideone)
#include <iostream>
struct Object;
Object * g_pObject;
struct Object
{
Object():m_a(0){}
void ModifySelfViaConstMethod() const
{
g_pObject->m_a = 37;
}
int m_a;
};
int main()
{
Object o;
g_pObject = &o;
const Object & co = o;
std::cout << co.m_a << "\n";
co.ModifySelfViaConstMethod();
std::cout << co.m_a << "\n";
return 0;
}
Я не очень хорошо разбираюсь в стандартах C++, поэтому спрашиваю здесь:
Что по этому поводу говорит стандарт?
а)const
метод не гарантирует вам, что ваш объект останется неизменным, когда вы делаете такие вещи
б) Это четко определено и должно быть скомпилировано
в) другое?
Решение
Что стандарт говорит об этом?
Он говорит (перефразирование), что this
имеет тип const Object *
, так что вы не можете напрямую изменять элементы или вызовать функции членов Non-Const через this
. Это ничего не говорит о том, что вы можете сделать с любыми глобальными переменными, к которым функция может иметь доступ к; Он только контролирует прямой доступ к объекту, на которой вызывается функция.
Способ
const
не гарантирует вас, что ваш объект остается неизмененным, когда вы делаете такие вещи
Нет, это не так. Он заявляет о намерении, что функция не модифицирует объект, и обеспечивает некоторую защиту от случайного нарушения этого намерения. Он не предотвращает использование подходящего небуманного программиста с использованием const_cast
или (как здесь) неконтролируемая связь через глобальные переменные, чтобы нарушить обещание.
Это четко определено, что и он должен компилировать
Да. o
не сам по себе постоянна, поэтому нет ничего, чтобы остановить, что вы принимаете указатель или ссылку на нее. Генеракодицетагкод на функцию элементов ограничивает доступ к объекту через const
, а не произвольными объектами по другим указателям.
Другие советы
Когда вы объявляете const
функция, это "для вашего же блага".
Другими словами, вы заявляете об этом const
потому что, согласно вашему первоначальному дизайну, не предполагается изменять какой-либо объект, с помощью которого он будет вызван во время выполнения.
Если на каком-то более позднем этапе реализации этой функции вы в конечном итоге измените объект, компилятор "накричит на вас", сообщив, что это неправильно.
Конечно, компилятор сможет идентифицировать такую попытку только при применении к this
.
В приведенном примере компилятор не может идентифицировать проблему, поскольку для этого требуется сравнение между this
и g_pObject
, и такое сравнение может иметь место только во время выполнения.
Когда метод объявлен как const
, компилятор гарантирует, что экземпляр, на который указывает this
указатель не изменяется.Если вы попытаетесь изменить this
например, компилятор потерпит неудачу.Однако компилятор не имеет возможности узнать об этом. g_pObject
и this
на самом деле указывают на один и тот же экземпляр.Для этого требуется сравнение во время выполнения, и ни один компилятор не будет тратить время на сравнение во время выполнения каждого указателя, используемого внутри const
метод на тот случай, если они мощь соответствовать this
указатель.Итак, если вы собираетесь изменить Object
через внешний указатель вам придется выполнить собственную проверку, например:
void ModifySelfViaConstMethod() const
{
if (g_pObject != this)
g_pObject->m_a = 37;
}
Постоянство в C ++ - это инструмент безопасности, а не защита.
Код, в котором соблюдается постоянство, скорее всего, будет работать так, как ожидалось, и все непреднамеренные попытки отбросить постоянство будут предупреждены компилятором.
В случаях, когда "Я знаю, что я делаю", можно найти все разнообразие инструментов, начиная с const_cast
оператор и mutable
ключевое слово для приведения в банальном стиле C.