Russian Qt Forum

Программирование => С/C++ => Тема начата: Igors от Октябрь 05, 2019, 08:22



Название: const до/после *
Отправлено: Igors от Октябрь 05, 2019, 08:22
Добрый день

Код
C++ (Qt)
#include <QSet>
QSet<int *> theSet;
 
void Test( const int * ptr )
{
theSet.insert(ptr);
}
 
Не компилится, говорит что надо так
Код
C++ (Qt)
void Test( int * const ptr )
{
theSet.insert(ptr);
}
 
Ну ладно, хотя никакой возможности изменить помещенное нет.
Но почему так компилит
Код
C++ (Qt)
typedef int * TInt;
void Test( const TInt ptr )
{
theSet.insert(ptr);
}
 
??? ??? (ту статью Алены читал)

Спасибо


Название: Re: const до/после *
Отправлено: Old от Октябрь 05, 2019, 08:46
А вы разницу между этими записями понимаете?
Если вы проговорите словами, те типы которые вы написали, то все станет ясно.


Название: Re: const до/после *
Отправлено: _Bers от Октябрь 06, 2019, 14:11
Не компилится, говорит что надо так
Код
C++ (Qt)
void Test( int * const ptr )
{
   theSet.insert(ptr);
}
 


квалификатор const не обязателен.
Код:
void Test(int* ptr)
{
    theSet.insert(ptr);
}

тебе нужно понять разницу между type* const и const* type


Название: Re: const до/после *
Отправлено: Igors от Октябрь 07, 2019, 08:03
Вопрос был о роли typedef в этом деле
Код
C++ (Qt)
// оказывается такая запись
typedef int * PInt;
const PInt a;
 
// равнозначна такой (константный указатель)
int * const a;
 
// а вовсе не такой (указатель на константу)
const int * a;
Чего это?


Название: Re: const до/после *
Отправлено: Old от Октябрь 07, 2019, 08:16
Чего это?
А что вас собственно удивляет? :)

Тайпдеф определяет указатель на не константные данные, а потом вы определяете константную переменную этого типа.
typedef != #define, как вы его себе представляете.


Название: Re: const до/после *
Отправлено: Авварон от Октябрь 08, 2019, 14:11
Чего это?

Типы читаются справа налево. Поэтому const int c = 42 не совсем каноничная и понятная запись, более логично было бы int const c = 42 (и да, так можно!). Видимо, для удобства кожаных ублюдков (которые читают слева направо) было сделано исключение (ну а чо, удобно же).

PInt p; p - это указатель на (неконстантный) int.
const PInt p; p - это константный указатель на int (привет, исключение) . Аналогично PInt const
int * const p; тоже самое
const int * const p; p - это константный указатель на константный int (снова исключение)
int const * const p; p - тоже самое


Название: Re: const до/после *
Отправлено: ViTech от Октябрь 08, 2019, 15:08
Видимо, для удобства кожаных ублюдков (которые читают слева направо) было сделано исключение (ну а чо, удобно же).

Интересно, что помешало изначально сделать написание типов с указателями/ссылками удобным для кожаных ублюдков? :)

Чтобы было не:
const X * const p - means “p is a const pointer to an X that is const” (right-to-left),
а
const * const X p  - means "p is a const pointer to a const X" (left-to-right).

Кстати, некоторые кожаные и справа налево читают. А ещё некоторые вообще сверху вниз, справа налево :).


Название: Re: const до/после *
Отправлено: Авварон от Октябрь 08, 2019, 16:57

Интересно, что помешало изначально сделать написание типов с указателями/ссылками удобным для кожаных ублюдков? :)

Возможно, вырвиглазной синтаксис функций принимающих указатели на функции берущих указатели на функции.
Впрочем, так и сделали в простом случае=)


Название: Re: const до/после *
Отправлено: ViTech от Октябрь 08, 2019, 17:28
Возможно, вырвиглазной синтаксис функций принимающих указатели на функции берущих указатели на функции.

Может быть. Похоже, истоки надо в языке С искать. Может тогдашним парсерам так было проще текст разгребать. Т.е. сначала кожаные прогнулись под тупые железяки, а потом начали разгибаться. Но так до конца и не выпрямились :).


Название: Re: const до/после *
Отправлено: Igors от Октябрь 09, 2019, 05:36
Типы читаются справа налево.
Пробовал представить как это, но чижело. Напр
Код:
const int * a;
Начинаем с int. Сначала к нему применяется const (получаем константный int), а затем звездочку, в итоге указатель на константный int - вроде верно. Т.е. сначала слева, потом справа, так что ли.

Все-таки интересно с typedef, выходит он играет роль скобок, но где это написано?  :)


Название: Re: const до/после *
Отправлено: ViTech от Октябрь 09, 2019, 09:39
Пробовал представить как это, но чижело. Напр
Код:
const int * a;
Начинаем с int. Сначала к нему применяется const (получаем константный int), а затем звездочку, в итоге указатель на константный int - вроде верно. Т.е. сначала слева, потом справа, так что ли.

What does “const X* p” mean? (https://isocpp.org/wiki/faq/const-correctness)
Цитировать
Read it right-to-left: “p is a pointer to an X that is constant.”


Название: Re: const до/после *
Отправлено: Igors от Октябрь 09, 2019, 16:18
What does “const X* p” mean? (https://isocpp.org/wiki/faq/const-correctness)
Цитировать
Read it right-to-left: “p is a pointer to an X that is constant.”
Применим правило "справа налево" к др случаю
Код:
int * const a;
Начинаем с const (самый правый). И.. что? const "для чего"? Как это понимать? С др стороны если начать с базового int - все вполне стройно.


Название: Re: const до/после *
Отправлено: kambala от Октябрь 09, 2019, 16:54
constant pointer to int (константный указатель на инт)


Название: Re: const до/после *
Отправлено: ViTech от Октябрь 09, 2019, 17:59
What does “const X* p” mean? (https://isocpp.org/wiki/faq/const-correctness)
Цитировать
Read it right-to-left: “p is a pointer to an X that is constant.”
Применим правило "справа налево" к др случаю
Код:
int * const a;
Начинаем с const (самый правый). И.. что? const "для чего"? Как это понимать? С др стороны если начать с базового int - все вполне стройно.

По той же ссылке в следующем пункте:
Цитировать
X* const p means “p is a const pointer to an X that is non-const”: you can’t change the pointer p itself, but you can change the X object via p.
RTFM (http://lurkmore.to/RTFM).


Название: Re: const до/после *
Отправлено: Igors от Октябрь 10, 2019, 11:26
constant pointer to int (константный указатель на инт)
Конкретно этот случай всем известен, просто запомнить его несложно. Интересны общие "правила чтения (навороченного) типа". Говорят "справа налево". Хорошо
Код:
int * const
Стало быть, const применяется ко всему что слева. Годится (здесь мы знаем "правельный ответ"). Ну а здесь
Код:
const int *
Слева никого нету. И шо ???


Название: Re: const до/после *
Отправлено: sergek от Октябрь 10, 2019, 11:49
Код:
const int *
Слева никого нету. И шо ???
Тогда зацикливаем выражение, типа переносим вправо ))
Код:
 int * var const
указатель на константу типа int.
Страуструп говорил, что лишь "некоторые люди находят удобным читать такие объявления справа налево. Еще он утверждал, что "никакого декларатора const* не существует" (в кавычках - цитаты). Очень многие правила - с исключениями))


Название: Re: const до/после *
Отправлено: Авварон от Октябрь 10, 2019, 17:36
Слева никого нету. И шо ???

модификаторы типа T могут стоять как справа, так и слева от Т:
int volatile const a;
и рассматриваются как единое целое

Под T подразумевается корректный идентификатор (т.е. некое имя типа без звездочек скобочек и прочего).
Всё остальное читается справа налево (звездочки, ссылки, скобочки).
Видим звездочку - говорим "указатель на" и читаем дальше. Видим T, читаем вперед пока не дойдем до конца или не встретим следующий "разделитель" (звездочку, например).
Вас же не удивляет наличие оператора ++ как же так, два плюса подряд, ведь после плюса должно выражение быть. А еще можно написать 5 + +10 вообще кошмар.


Название: Re: const до/после *
Отправлено: Igors от Октябрь 11, 2019, 09:31
модификаторы типа T могут стоять как справа, так и слева от Т:
int volatile const a;
и рассматриваются как единое целое
Существенно, спасибо

Но мы несколько зациклились на избитых примерах. А ну чуть копнем
Код
C++ (Qt)
void Test( const int ** a )
{
 a = 0;   // ok
 *a = 0;  // ok
//  **a = 0;  // error
}
Часто это и нужно, напр есть массив неперемещаемых данных, нужно сортировать его так и сяк, потом работать с сортированным. Ну делаем массив указателей, сортируем его и обрабатываем ф-цией Test выше. Однако

Код
C++ (Qt)
int data = 5;
std::vector<int *> vecPtr;
vecPtr.push_back(&data);
Test(&vecPtr[0]);      // error
const int ** test = &vec[0]; // error
И никак  :'( ("пока не купите стиральную машину "Вятка"), т.е. пока не изменить тип вектора на const int *. Что не очень удобно - это я в Test хочу константные данные - а напр в Test2 могу и менять

ЧЯДНТ?


Название: Re: const до/после *
Отправлено: ViTech от Октябрь 11, 2019, 13:06
ЧЯДНТ?

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

Это же очень трудно, оформить пример (https://coliru.stacked-crooked.com/a/78dac022e63fc2e8) в таком виде:
Код
C++ (Qt)
#include <vector>
#include <iostream>
 
using namespace std;
 
void test(int** p)
{
   cout << "mutable int = " << **p << endl;
}
 
void test(int const* const* p)
{
   cout << "const   int = " << **p << endl;
}
 
int main()
{
   int data = 5;
   vector<int*> vecPtr;
   vecPtr.push_back(&data);
 
   test(&vecPtr[0]);
   test(static_cast<int const* const*>(&vecPtr[0]));
 
   return 0;
}


Название: Re: const до/после *
Отправлено: Igors от Октябрь 12, 2019, 09:28
Код
C++ (Qt)
   test(static_cast<int const* const*>(&vecPtr[0]));
}
Это "лучше чем ничего", но полноценным не является, константные указатели никто не заказывал. Интересно что
Код
C++ (Qt)
test(const_cast<const int **>(&vecPtr[0]));
Проходит. Оказывается const_cast умеет не только "снимать" константность :) При упоминании о const_cast немедленно сыпятся упреки "корявая архитектура" (хотя архитектура-то здесь причем?), "костыль" и.т.п. Ну а здесь чем он плох? Что может сломаться (при любых "если"). Не вижу
 


Название: Re: const до/после *
Отправлено: ViTech от Октябрь 12, 2019, 10:52
Это "лучше чем ничего", но полноценным не является, константные указатели никто не заказывал.

А Вы собираетесь в функции, которая работает с const int, менять указатели? И там именно одиночный int, а не что-то другое?

Интересно что
Код
C++ (Qt)
test(const_cast<const int **>(&vecPtr[0]));
Проходит. Оказывается const_cast умеет не только "снимать" константность :) При упоминании о const_cast немедленно сыпятся упреки "корявая архитектура" (хотя архитектура-то здесь причем?), "костыль" и.т.п. Ну а здесь чем он плох? Что может сломаться (при любых "если"). Не вижу

Вы же до конца дочитали Const Correctness FAQ по ссылке, что я давал? Если Вы не видите, что что-то может сломаться, значит оно не сломается. Не слушайте всяких теоретиков, компиляторщиков, пишите const_cast'ов побольше, Вы же лучше знаете :).


Название: Re: const до/после *
Отправлено: m_ax от Октябрь 12, 2019, 15:29
Цитировать
Вы же до конца дочитали Const Correctness FAQ по ссылке, что я давал? Если Вы не видите, что что-то может сломаться, значит оно не сломается. Не слушайте всяких теоретиков, компиляторщиков, пишите const_cast'ов побольше, Вы же лучше знаете  :)
Мне думается, что у Igorsа проблема гораздо глубже лежит  :)


Название: Re: const до/после *
Отправлено: Igors от Октябрь 12, 2019, 16:39
А Вы собираетесь в функции, которая работает с const int, менять указатели? И там именно одиночный int, а не что-то другое?
Почему нет? Ну хотя бы эти указатели нужно сортировать

Вы же до конца дочитали Const Correctness FAQ по ссылке, что я давал? Если Вы не видите, что что-то может сломаться, значит оно не сломается. Не слушайте всяких теоретиков, компиляторщиков, пишите const_cast'ов побольше, Вы же лучше знаете :).
Не стоит раздражаться. Да, const_cast не есть хорошо, и, прежде чем его писать, надо еще раз подумать как обойтись без него. Но если, как в данном случае, лучшего не видно - ну значит const_cast, на всякое правило есть исключение. Кстати и в исходниках Qt они совсем не "музейная редкость"


Название: Re: const до/после *
Отправлено: m_ax от Октябрь 12, 2019, 21:46
Я просто не понимаю, чем обусловлено использование таких конструкций
Код
C++ (Qt)
int data = 5;
std::vector<int *> vecPtr;
vecPtr.push_back(&data);
Test(&vecPtr[0]);      // error
const int ** test = &vec[0]; // error
 
в современном c++  :)


Название: Re: const до/после *
Отправлено: _Bers от Октябрь 13, 2019, 02:52
Код
C++ (Qt)
// оказывается такая запись
typedef int * PInt;
const PInt a;
 
// равнозначна такой (константный указатель)
int * const a;
 
// а вовсе не такой (указатель на константу)
const int * a;
Чего это?

const T - T является константой.
если T - указатель, значит указатель и является константой
незменяемый указатель имеет вид: type* const

как вообще это можно было неправильно понять?


Название: Re: const до/после *
Отправлено: _Bers от Октябрь 13, 2019, 02:55
Видимо, для удобства кожаных ублюдков (которые читают слева направо) было сделано исключение (ну а чо, удобно же).

кто такие "кожанные ублюдки" ?



Название: Re: const до/после *
Отправлено: ViTech от Октябрь 13, 2019, 09:51
Я просто не понимаю, чем обусловлено использование таких конструкций
...
в современном c++  :)

У меня есть версия, что там не современный С++, а старый Си с классами, хоть и в новой обёртке :).


Название: Re: const до/после *
Отправлено: Авварон от Октябрь 13, 2019, 15:55

кто такие "кожанные ублюдки" ?



https://www.youtube.com/watch?v=4TpeG-nQhJ4


Название: Re: const до/после *
Отправлено: AkonResumed от Апрель 20, 2021, 07:35
Как насчет следующей формализации при объявлении переменных сложных типов:

1. Тип просто определяет размер области памяти (он, конечно, определяет много чего еще, но нам здесь это неважно). Более никаких атрибутов тип не имеет, т.е. const - это не про тип. Когда объявляется переменная типа, то мы получаем конкретный кусок памяти, характеризуемый размером и адресом. И вот тут уместно определить атрибут доступа к этому конкретному куску - если только чтение, то const. Т.е. const - это атрибут конкретного адреса памяти, а не типа.

2. const пишется всегда слева и воздействует на то, что справа. 'const T' - запрещено, т.к. из п.1 мы определели, что "const - это не про тип".

3. Будем считать косвенный доступ '*' (т.е. доступ через указатель) как отдельную сущность с атрибутом доступа 'запись и чтение' или 'только чтение', т.е. '*' и 'const *' (как приняли в п.2, const пишется всегда слева).

Итак, следуя этой формализации, константный указатель на константные данные типа int (или прямо - типа int константных данных константный указатель) пишется так:
Код:
int const * const p;
Компоненты: int - тип, const * - косвенность доступа (в данном случае только для чтения), const p - адрес памяти (в данном случае только для чтения).

Вообщем 'const int*' и 'int const *' это как, например, 'спиртовой раствор' и 'спирта раствор'. 1-е для обывателей, 2-е - для технарей/профи :), потому что здесь главное (спирт) выноситсяна первое место, например, удобно строить алфавитный указатель.