LINUX.ORG.RU

С++ : Как понимать фразу «сам указатель является константным»?


0

1

Вот в этой книге:

http://www.plam.ru/compinet/yeffektivnoe_ispolzovanie_c_55_vernyh_sposobov_ul...

есть следующая фраза (речь идет о модификаторе const и объявлении указателя):

Если слово const появляется слева от звездочки, константным является то, на что указывает указатель; если справа, то сам указатель является константным.



Вопрос: что скрывается под фразой «сам указатель является константным»?

С точки зрения машинного кода, указатель - это ячейка памяти, в которой хранится адрес значения, на которое указывает указатель. При обращении к указателю, компилятор по имени указателя вычисляет адрес ячейки памяти указателя, берет из нее адрес значения. И дальше использует этот адрес значения (обычно обращение происходит через инструкцию LEA).

«Сам указатель является константным» - это значит, что:

Вариант 1

... в ячейке памяти указателя может храниться только один адрес, заданный при инициализации. Соответственно, указатель может ссылаться только на одну-единственную ячейку памяти, адрес которой был задан при инициализации.

Вариант 2

... адрес ячейки указателя является константой. Компилятор всего лишь гарантирует, что адрес ячейки указателя не будет меняться в течении времени жизни указателя. Так как это и так очевидно, то особого смысла в конструкции «сам указатель является константным» нет, хотя и поддерживается языком.

Какой вариант правильный? Или правильным будет какой-то третий вариант?

★★★★★

Я познаю мир, опять и снова.

false ★★★★★ ()

незнаю, что меня больше раздражает: тупорылая аватарка или тупорылые топики.

x0r ★★★★★ ()

«Сам указатель является константным» - это значит, что:

указатель нельзя сдвинуть. Хотя можно поменять то, на что он указывает (константный указатель на неконстанту). Или нельзя (константный указатель на константу).

emulek ()

Какой вариант правильный?

1.

Manhunt ★★★★★ ()
int main() {
	int i = 0;
	
	const int * a = &i;
	int const * b = &i;
	int * const c = &i;
	const int * const d = &i;

	return 0;
}
yoghurt ★★★★★ ()
Последнее исправление: yoghurt (всего исправлений: 1)
Ответ на: комментарий от emulek

это значит, что:

указатель нельзя сдвинуть.

А это вариант 2 (адрес ячейки указателя является константой).

Но тут утверждают, что правильный вариант 1.

Кто прав?

Xintrea ★★★★★ ()
Ответ на: комментарий от Xintrea

при наличии const_cast<> (да и просто C-style cast) оба варианта и правильные и неправильные одновременно.

yoghurt ★★★★★ ()
Ответ на: комментарий от x0r

незнаю, что меня больше раздражает: тупорылая аватарка или тупорылые топики.

Сматри, я нарисовал себе еще одну тупорылую аватарку:

http://webhamster.ru/db/data/gallery/10/sobachka_besumnaia.gif

Она даже еще более тупорылее, чем крыса. Но я пока пожалею лошадь, и оставлю предыдущую.

Xintrea ★★★★★ ()
Ответ на: комментарий от Xintrea

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

yoghurt ★★★★★ ()

как много среди регистрантов высокомерного отребья

anonymous ()
Ответ на: комментарий от Xintrea

А это вариант 2 (адрес ячейки указателя является константой).

извини. Это я ошибся. Конечно const char *x; можно направить куда угодно, в т.ч. и в никуда(x=NULL;), а изменять нельзя *x. Например (*x)++ даст ошибку. А вот *x++ напротив — не даст, ибо ++ старше чем *.

emulek ()
Ответ на: комментарий от yoghurt

при наличии const_cast<> (да и просто C-style cast) оба варианта и правильные и неправильные одновременно.

потому-что cast это костыль. Ты одновременно и инвалид по ногам, и можешь ходить(потому что костыли).

emulek ()
Ответ на: комментарий от gh0stwizard

https://en.wikipedia.org/wiki/Const-correctness

Я попытался перевести пример из раздела Pointers and references.

void Foo( int * ptr,
          int const * ptrToConst,
          int * const constPtr,
          int const * const constPtrToConst )
{
    *ptr = 0; // OK: изменяются данные, на которые указывает указатель
    ptr  = NULL; // OK: изменяется указатель (т. е. изменяется адрес, содержащийся в указателе)
 
    *ptrToConst = 0; // Ошибка: невозможно изменить данные, на которые указывает указатель
    ptrToConst  = NULL; // OK: изменяется указатель (т. е. изменяется адрес, содержащийся в указателе)
 
    *constPtr = 0; // OK: изменяются данные, на которые указывает указатель
    constPtr  = NULL; // Ошибка: невозможно изменить указатель (т. е. невозможно изменить адрес, содержащийся в указателе)
 
    *constPtrToConst = 0; // Ошибка: невозможно изменить данные, на которые указывает указатель
    constPtrToConst  = NULL; // Ошибка: невозможно изменить указатель (т. е. невозможно изменить адрес, содержащийся в указателе)
}

Правильно, или я что-то неверно понял?

Xintrea ★★★★★ ()
Ответ на: комментарий от emulek

Сорри, щас вдохновения нет, и навык частично утерян.

Xintrea ★★★★★ ()
Ответ на: комментарий от Xintrea

всё правильно. Разве сложно самом скомпиллить с -Wall, компиллятор всё скажет

emulek ()
Ответ на: комментарий от emulek

Хотя да, после каста это будет уже другой указатель, с которым компилятор уже ничего не гарантирует

yoghurt ★★★★★ ()
Ответ на: комментарий от yoghurt

кстати, если ты применишь каст к неконстантному к указателю, который объявлен как константный, то AFAIK это UB.

AFAIK const_cast можно применять только к тому, что изначально было НЕ константой, но стало константой по другим причинам. Т.е что-бы избежать ещё худшего костыля mutable.

emulek ()
Ответ на: комментарий от emulek

например константный метод коллекции очевидно не может изменять саму коллекцию. Однако он может поменять какой-то эл-т коллекции. Т.е. например коллекция типа «список» может содержать метод, который ничего не удаляет и не добавляет к списку(и потому константный), однако как-то изменяет сам эл-т списка. Вот тут нужен const_cast ИМХО.

emulek ()
Ответ на: комментарий от Xintrea

как не странно, но собачка выглядит лучше. и все же нарисуй пони.

x0r ★★★★★ ()

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

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

Harald ★★★★★ ()

С какого лешего это тебе константность указателей «и так очевидна»? Он, прикинь, еще и volatile может быть.

anonymous ()
Ответ на: комментарий от Harald

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

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

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

emulek ()
Ответ на: комментарий от emulek

нее, это будет уже указатель на этот указатель

Harald ★★★★★ ()
Ответ на: комментарий от Harald

нее, это будет уже указатель на этот указатель

указатель на указатель это адрес, по которому лежит другой адрес. А вот ссылка на указатель — это как раз адрес, который в другом месте памяти находится. Путём говнокода(например с reinterpret_cast) такую ссылку можно преобразовать в int, прибавить размер, и обратно. И получим ссылку, которая указывает не туда, куда сам указатель (конечно такой говнокод может и нее сработать. UB оно и есть UB, т.ч. пруфов не будет, сам говнокодь)

emulek ()

еще тема: читай объявления указателей справа налево.

const int * n; // n - указатель на const int
int * const n; // n - константный указатель на int

итп

unt1tled ★★★★ ()
Последнее исправление: unt1tled (всего исправлений: 1)
Ответ на: комментарий от emulek

указатель на указатель это адрес, по которому лежит другой адрес

не обязательно .

т.е компилятор(и просто реализация и оптимизатор) может сам указатель держать в коде(если одноразовый, или полиморфизм кода)или в регистре.

т.е степень косвенности в реализации может быть меньше чем в сырце - на этом кста очень часта куча грабль выстреливает.

qulinxao ★★☆ ()
Ответ на: комментарий от qulinxao

т.е компилятор(и просто реализация и оптимизатор) может сам указатель держать в коде(если одноразовый, или полиморфизм кода)или в регистре.

ИМХО ТСу это пока не нужно знать. Но в целом, да, конечно.

emulek ()
int x = 13;
int *const p1 = &x;

p1++; // ошибка

int *p2 = p1; // warning, но скомпилируется
p2++;
*p2 = 37; // жопа
anonymous ()
Ответ на: комментарий от qulinxao

Вот, этого ответа я ждал. Складывается впечатление, что 90 перцентов отписавшихся вообще не понимают как работает прога на железе. Они живут в каких-то идеальных мирах, и считают свои ограниченные знания очевидными.

Xintrea ★★★★★ ()
Ответ на: комментарий от emulek

да мне не срочно надо. Потом как-нить

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

http://webhamster.ru/site/page/index/draw/0/2/

Там есть вот такой крокодайл, на случай если захочется порвать кого-то вхлам:

http://webhamster.ru/db/data/gallery/2/gde_obed.gif

Или из других разделов, претензий иметь не буду.

Xintrea ★★★★★ ()
Ответ на: комментарий от false

Это же чудесно :) Когда перестанешь, настанет скука и деградация.

coderage ()

Правильнее всего эту фразу понимать дословно.

слово const появляется слева от звездочки
слева от звездочки

Пальцы непроизвольно сжимаются в кулак.

(А ведь когда-то я всерьез надеялся, что поделие ТСа дорастет до вменяемого менеджера информации)

thesis ★★★★★ ()
Ответ на: комментарий от Xintrea

Растет - это хорошо, это здорово.
Будет нефиг делать - всунь иконку для венды, а? Красота же превыше всего.

thesis ★★★★★ ()
Ответ на: комментарий от yoghurt

О, круто, когда в следующий раз приплюснутые на джавистов будут бузить в стиле «Apple apple = new Apple() - это страшно», я буду показывать давать ссылку на этот пост.

anonymous ()

Твои вопросы просто жгут!))) Почитай теорию для начала, я смотрю с указателями ты совсем не дружишь.

golodranez ★★★★ ()
Ответ на: комментарий от yoghurt

Ненавижу этот ублюдочный синтаксис. Именно поэтому плюсы должны умереть.

LongLiveUbuntu ★★★★★ ()
Ответ на: комментарий от Xintrea

Складывается впечатление, что 90 перцентов отписавшихся вообще не понимают как работает прога на железе. Они живут в каких-то идеальных мирах, и считают свои ограниченные знания очевидными.

ты так ничего и не понял. Суть в том, что НЕ НУЖНО этого знать. Смотри:

1. я пишу код, который корректен с т.з стандарта

2. ты пишешь код, который корректен с т.з. amd64-процессора

Надеюсь ты понимаешь, почему ты говнокодер, а я — нет? Объясню: твой говнокод работает только на твоём локалхосте. А мой — где угодно(где есть компилятор).

В этом суть сишечки, и именно для этого её и придумали. И именно потому я не знаю, и не хочу знать, сколько бит в int'е. Или сколько в ptrdiff_t.

Т.е. сишечка == некая виртуальная машина, которой нет. Программа пишется в терминах этой виртуальной машины. Потом она компилируется, и подгоняется по месту компилятором.

Важно то, что константный указатель не меняется, а значит компилятор _может_ не выделять для него место в памяти, как это он делает для любых переменных. Вот пример без всяких указателей(x86/2014) :

int x = 4;// выделяется 4 байта памяти, в которые пишется число 4
const int x = 4;// НЕ выделяется память, компилятор просто запоминает, что x это 4
// далее где-то рядом
y *= x;// эта команда в первом случае (x == переменная) разворачивается всегда в IMUL, т.е. в команду умножения данного процессора
// но если x это константа, то разворачивается в SHL EAX, 2
// gcc сам может помнить про константность, даже если об этом не писать,
// однако долго он об этом не помнит.

т.е. фишка const это вовсе ни какие-то «запреты», а наоборот — разрешение для компилятора. Мы разрешаем компилятору НЕ хранить переменную в памяти, т.к. она никогда не меняется. Прямо противоположным смыслом обладает слово volatile, которое НЕ разрешает компилятору считать число «константой». Очевидно это нужно только для разделяемых ресурсов, для которых компилятор не видит, что оно _может_ измениться.

Если ничего не писать, то компилятор пытается сам считать переменную const, если это возможно.

emulek ()
Ответ на: комментарий от LongLiveUbuntu

Ненавижу этот ублюдочный синтаксис. Именно поэтому плюсы должны умереть.

у меня для тебя плохие новости: ты умрёшь раньше.

emulek ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.