Есть две точки зрения на использование const
.
Первая: const
- это плохо. От него больше хлопот, чем пользы, ошибки какие-то странные вылезать начинают, лучше им не пользоваться.
Вторая: const
- это хорошо. const
не дает менять объекты, которые не должны меняться, таким образом оберегает от ошибок, его надо использовать везде где только можно.
Я придерживаюсь второй точки зрения.
В английской литературе можно часто встретить термины const correctness и const correct code, для кода, который корректно использует const
. const
имеет немного разный смысл в зависимости от того где находится. В C++ FAQ Lite вопросу Const correctness посвящен отдельный раздел.
Объявление переменных
Самый простой случай, обычная переменная. Переменная объявляется, тут же инициализируется, менять ее значение больше нельзя.
const int p=4;
p=5; //ошибка
Про использование const
с указателями есть известный C++ паззл, который любят давать на собеседованиях при приеме на работу.Чем отличаются
int *const p1
int const* p2
const int* p3
Правило тут такое: провести мысленно вертикальную черту по звездочке. То, что находится справа относится к переменной. То, что слева - к типу, на который она указывает. Вот например:int *const p1
Cправа находится p1
, и это p1
константа. Тип, на который p1
указывает, это int
. Значит получился константный указатель на int
. Его можно инициализировать лишь однажды и больше менять нельзя.Нужно так:
int q=1;
int *const p1 = &q; //инициализация в момент объявления
*p1 = 5; //само число можно менять
Вот так компилятор не пропустит, потому что идет попытка присвоения константе:int q=1;
int *const p1;
p1 = &q; //ошибка
Объявленияint const* p2
const int* p3
это по разному записанное одно и то же объявление. Указатель на целое, которое нельзя менять.int q=1;
const int *p;
p = &q; //на что указывает p можно менять
*p = 5; //ошибка, число менять уже нельзя
Обычно в реальных программах используется вариант объявления const int
, а int const
используется, чтобы запутать на собеседовании.const
можно использовать со ссылками, чтобы через ссылку нельзя было поменять значение переменной.int p = 4;
const int& x=p; //нельзя через x поменять значение p
x=5; //ошибка
Константная ссылка - это нонсенс. Она по определению константная. Компилятор скорее всего выдаст предупреждение, что он проигнорировал const
.int& const x; //не имеет смысла
Передача параметров в функцию
const
удобен, если нужно передать параметры в функцию, но при этом надо обязательно знать, что переданный параметр не будет изменен.void f1(const std::string& s);
void f2(const std::string* sptr);
void f3(std::string s);
В первой и второй функции попытки изменить строку будут пойманы на этапе компиляции. В третьем случае в функции будет происходить работа с локальной копией строки, исходная строка не пострадает.Приведение Foo** к const Foo** приводит к ошибке
Потому что такое приведение может позволить менять объекты, которые константны.
class Foo
{
...
public:
void modify(); //вносит какие-либо изменения
};
int main()
{
const Foo x;
Foo* p;
const Foo** q = &p; // q теперь указывает на p; и это ошибка
*q = &x; // p теперь указывает на x
p->modify(); // попытка изменить const Foo!!
}
Самый простой способ это исправить это поменять const Foo**
на const Foo* const*
.В следующих постах речь пойдет об использовании
const
для данных и функций классов, а также о mutable
и const_cast
.Ссылки по теме:
[18] Const correctness, C++ FAQ Lite
comp.lang.c++.moderated is const correctness a dogma ?
Technorati tag: cpp
28 коммент.:
Прекрасно изложен материал, спасибо!
Сложные вещи простыми словами!!! Спасибо! Большое прибольшое спасибо!
Спасибо!!
Спасибо!
Мне, кажется, имеет смысл еще осветить следующую ситуацию:
class A
{
private:
std::vector {B*} lData;
public:
void addData(B* data);
B* getData(const int i) const;
}
Примечание: Не смог написать треугольные скобочки при инстанциировании шаблона - написал {}
Нужно добавить, что класс A устроен так, что элементы lData вообще нет смысла менять или даже удалять из списка. Например, если класс A некая функциональная обертка над B. Но создавать вектор указателей на константы плохо (в какой-то книге об этом говорилось). Тут нужен компромисс :) и поэтому не смотря на то, что addData не меняет передаваемый указатель и объект на который он указывает const ставить не стоит.
Уважаемая Алёна!
Не могли бы вы помочь разобраться с следующей ситуацией?
const int x=10;
int* p=const_cast(&x);
*p=11;
cout << x << endl;
На экране 10, но непонятно, почему... Что тут происходит? Куда указывает p?
Он точно указывает не на x, т.к. добавив cout << *p << endl; на экране будет как 10, так и 11. Значит p указывает куда-то кроме икса, но куда? Кто выделял память под эту 11?
Я предполагаю, что p указывает на временную переменную, созданную во время вычисления выражения с приведением типа, но... не уверен :(
Разве временная переменная не должна быть уничтожена после вычисления выражения?
2DWord:
На экране 10, но непонятно, почему... Что тут происходит? Куда указывает p?
Вы снимаете const с переменной, которая была изначально объявлена как const. По Стандарту это ведет к неопределенному поведению (7.1.5.1).
Хм.. вообще логично :)
Благодарю за помощь!
И спасибо за статью! Побудила разобраться в тонкостях)
Возникло недопонимае вопроса
почему
const char *p1="maus";
char const *p2="elefant";
p1="rat";//ошибка
p2="krokodail";//ошибки нет
если это важно компилятор minGW
Прошу прощения , теперь разобрался пусть и перечитать пришлось несколько раз если я всеже неправ то прошу меня поправить
const char *p1="maus";
p1="rat";->видимо здесь происходит не изменение даных а присвоение нового адреса указателю,придется еще несколько раз прочитать работу указателей со строками
2leg:
Возникло недопонимае вопроса
почему
Не должно быть разницы, minGW меня удивил. Какие-то компиляторы это копиляют, какие-то нет. Такое присваивание - не очень хорошая идея. В случае p1 будет создана новая строка "rat", указателей на первую строку не останется. Причем модифицирование такой строки ведет к undefined behavior.
Если вам нужно просто работать со строками, используйте std::string.
2leg:
видимо здесь происходит не изменение даных а присвоение нового адреса указателю
Да, именно так
Спасибо за статью, действительно помогла разобратся с непонятными моментами.
Спасибо за статью.
А как использовать мнемоническое правило с чертой по звездочке в случае двойных и более указателей как на элементарные типы, так и на объекты, да еще и в аргументах функций(методов)?
nightshad0w
Спасибо за статью.
пожалуйста :-)
А как использовать мнемоническое правило с чертой по звездочке в случае двойных и более указателей как на элементарные типы, так и на объекты, да еще и в аргументах функций(методов)?
Вот тут про это много написано:
http://www.unixwiz.net/techtips/reading-cdecl.html
Здорово. Всё ясно =)
Алена, вы прсто умничка!
Большое спасибо,помогло!
Интересно, они серьёзно все считают, что const обязательно надо использовать?
Ребята, не верьте никому, даже мне.
(Мюллер)
g++.exe p.cpp -o p.exe -m32 -std=c++11
const char *p1="maus";
char const *p2="elefant";
p1="rat";//ошибки нет
p2="krokodail";//ошибки нет
;)
На экране 10, но непонятно, почему... Что тут происходит? Куда указывает p?
Готов поспорить, что если добавить volatile const int x = 10;
то на экран будет выведено 11. (Не смотря на undefined behavior)
Готов поспорить, что если добавить volatile const int x = 10;
то на экран будет выведено 11. (Не смотря на undefined behavior)
Ты прав. Сейчас проверил - и правда выводится 11
Алена я вас люблю!!
Алена, спасибо большое за статью!
Скажите, а как быть с этим вот:
int * const * p5
Я не могу понять.. это указатель на константный указатель или константный указатель на указатель? По сути должно быть верным второе (константный указатель на указатель, иначе зачем использовать const в данном случае). Но не до конца уверена, что я права.
Unknown
Я не могу понять.. это указатель на константный указатель или константный указатель на указатель?
Это указатель на константный указатель. По аналогии с int const* p2.
Это всегда можно проверить, написать небольшой тест и попробовать изменить p5 и то, куда оно указывает.
Зачем - отдельный вопрос, надо по коду смотреть.
Хочу заметить:
из статьи:
int q=1;
const int *p;
p = &q; //на что указывает p можно менять
*p = 5; //ошибка, число менять уже нельзя
предложение:
*p = 5; //ошибка значение переменной q нельзя менять с помощью указателя p
int *p2 = &q;
*p2 = 5; //ошибки нет значение переменной q можно!!! менять с помощью указателя p2
Хочу заметить:
из статьи:
int q=1;
const int *p;
p = &q; //на что указывает p можно менять
*p = 5; //ошибка, число менять уже нельзя
предложение:
*p = 5; //ошибка значение переменной q нельзя менять с помощью указателя p
int *p2 = &q;
*p2 = 5; //ошибки нет значение переменной q можно!!! менять с помощью указателя p2
предложение получше:
*p = 5; //ошибка значение переменной q нельзя менять с помощью указателя p
q = 5; //ошибки нет значение переменной q можно!!! менять с помощью q!!!! ЧУДО.
Спасибо большое! Очень доступно!
Отправить комментарий