Evgenii Legotckoi
Evgenii LegotckoiМаусым 5, 2017, 3:33 Т.Ж.

C++ - Сабақ 003. Тұрақтылар

Мазмұны

C++ поддерживает две нотации неизменности:

  1. const - которая подразумевает, что значение не будет изменяться. В первую очередь это используется для спецификации интерфейсов, для данных которые передаются в функции и методы так, чтобы не опасаться, что они будут изменены. Компилятор отслеживает наличие спецификатора const;
  2. constexp - который подразумевает вычисление константы во время компиляции. Используется для размещения данных в памяти, где они не будут повреждены, а также для улучшения производительности.

Например:

const int dmv = 17;                      // константа с именем dmv
int var = 17;                            // переменная var не является константой
constexpr double max1 = 1.4∗square(dmv); // OK, так как square(17) является константым выражением
constexpr double max2 = 1.4∗square(var); // Ошибка, так как var не является константой
const double max3 = 1.4∗square(var);     // OK, поскольку выражение может быть вычислено в рантайме
double sum(const vector<double>&);       // sum не будет модифицировать его аргументы
vector<double> v {1.2, 3.4, 4.5};        // v не является константой
const double s1 = sum(v);                // OK, будет вычислено в рантайме
constexpr double s2 = sum(v);            // Ошибка, sum(v) не является константным выражением.

Для того, чтобы функция использовалась в константном выражении, то есть, вычислялась компилятором, необходимо определить её со спецификатором constexpr .

constexpr double square(double x) { return x∗x; }

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

const

Объекты со спецификатором const не могут быть изменены, а также должны быть инициализированы.

const int model = 90;           // model является константой
const int v[] = { 1, 2, 3, 4 }; // v[i] является константой
const int x;                    // Ошибка: значение не инициализировано

Поскольку объекты со спецификаторов const не могут быть изменены, то следующий код будет ошибочным:

void f()
{
    model = 200; // Ошибка: model является константой
    v[2] = 3;    // Ошибка: v[i] является константой
}

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

void g(const X∗ p)
{
    // Не можем изменить p здесь
}

void h()
{
    X val;  // Но можем модифицировать значение здесь
    g(&val);
    // ...
}

При использовании указателя задействуются два объекта: сам указатель и объект, на который указывает. Префиксное' объявление указателя с const делает константным объект, а не указатель. Чтобы объявить как const сам указатель, а не объект, на который он указывает, необходимо поместить const после символа указателя. Например:

void f1(char∗ p)
{
    char s[] = "Gorm";

    const char∗ pc = s;        // указатель на константу
    pc[3] = 'g';               // Ошибка: значение объекта является константой
    pc = p;                    // OK

    char ∗const cp = s;        // константный указатель
    cp[3] = 'a';               // OK
    cp = p;                    // Ошибка: cp является константой

    const char ∗const cpc = s; // константный указатель на константный объект
    cpc[3] = 'a';              // Ошибка: объект является константой
    cpc = p;                   // Ошибка: указатель является константой
}

Местоположение const относительно базового типа не принципиально, поскольку не существует типа данных const*. Принципиальным является положение const относительно символа *. Поэтому возможны следующие записи:

char ∗const cp;  // const указатель на char
char const∗ pc;  // указать на const char
const char∗ pc2; // указатель на const char

Объект, который является константой при доступе через один указатель, может быть изменяемым при доступе иными способами. Это особенно полезно для аргументов функции. Объявляя аргумент указателя как const , функции запрещается изменять объект, на который указывает. Например:

const char∗ strchr(const char∗ p, char c);
char∗ strchr(char∗ p, char c);

Первая версия используется для строк, элементы которых не должны быть изменены функцией и возвращает указатель на const, который не позволяет изменять результат. Вторая версия используется для изменяемых строк.

Вы можете назначить адрес неконстантной переменной указателю на константу, потому что это не может нанести никакого вреда. Однако адрес константы нельзя назначить неконстантному указателю, поскольку это позволит изменить значение объекта. Например:

void f4()
{
    int a = 1;
    const int c = 2;
    const int∗ p1 = &c; // OK
    const int∗ p2 = &a; // OK
    int∗ p3 = &c;       // Ошибка: инициализация int* с const int*
    ∗p3 = 7;            // Попытка изменить значение c
}

constexpr

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

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

  1. Именованные константы упрощают понимание и поддержку кода.
  2. Переменная может быть изменена (поэтому мы должны быть более осторожными в наших рассуждениях, чем для константы).
  3. Язык требует постоянных выражений для размеров массивов, меток case и аргументов значений шаблона.
  4. Программисты встраиваемых систем любят помещать неизменяемые данные в постоянное запоминающее устройство. Потому что доступная только для чтения память дешевле, чем динамическая память (с точки зрения затрат и потребления энергии) и часто более многочисленная. Кроме того, данные в постоянной памяти защищены от большинства сбоев системы.
  5. Если инициализация выполняется во время компиляции, то в многопоточной программе системе не может быть никаких расхождений данных.
  6. Выполнение вычислений на этапе компиляции улучшает производительность программы.

Значение constexpr вычисляется во время выполнения компиляции, и если оно не может быть вычислено, то компилятор выдаст ошибку.

int x1 = 7;
constexpr int x2 = 7;
constexpr int x3 = x1;     // Ошибка: инициализатор не является константным выражением
constexpr int x4 = x2;     // OK

void f()
{
    constexpr int y3 = x1; // Ошибка: инициализатор не является константным выражением
    constexpr int y4 = x2; // OK
    // ...
}

Возможности константных выражений достаточно велики, поскольку имеется возможность использовать целочисленнные типы данных, данные с плавающей точкой, перечисления, а также операторы, которые не изменяют значения переменных (такие как +, ? и [] , но не = или ++ )

constexpr int isqrt_helper(int sq, int d, int a)
{
    return sq <= a ? isqrt_helper(sq+d,d+2,a) : d;
}

constexpr int isqrt(int x)
{
    return isqrt_helper(1,3,x)/2 − 1;
}

constexpr int s1 = isqrt(9);
constexpr int s2 = isqrt(1234);
Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Ол саған ұнайды ма? Әлеуметтік желілерде бөлісіңіз!

BlinCT
  • Маусым 5, 2017, 4:55 Т.Ж.

Отличное описание и примеры!

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
Г

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:66ұпай,
  • Бағалау ұпайлары-1
t

C++ - Тест 001. Первая программа и типы данных

  • Нәтиже:33ұпай,
  • Бағалау ұпайлары-10
t

Qt - Тест 001. Сигналы и слоты

  • Нәтиже:52ұпай,
  • Бағалау ұпайлары-4
Соңғы пікірлер
G
GoattRockҚыр. 3, 2024, 1:50 Т.Қ.
Linux жүйесінде файлдарды қалай көшіруге болады Задумывались когда-нибудь о том, как мы привыкли доверять свои вещи службам грузоперевозок? Сейчас такие услуги стали неотъемлемой частью нашей жизни, особенно когда речь идет о переездах между …
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssrАқп. 8, 2024, 6:43 Т.Қ.
Qt Linux - Сабақ 001. Linux астында Autorun Qt қолданбасы как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий КононенкоАқп. 5, 2024, 1:50 Т.Ж.
Qt WinAPI - Сабақ 007. Qt ішінде ICMP Ping арқылы жұмыс істеу Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
F
FynjyШілде 22, 2024, 4:15 Т.Ж.
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …
BlinCT
BlinCTМаусым 25, 2024, 1 Т.Ж.
Нарисовать кривую в qml Всем привет. Имеется Лист листов с тосками, точки получаны интерполяцией Лагранжа. Вопрос, как этими точками нарисовать кривую? ChartView отпадает сразу, в qt6.7 появился новый элемент…
BlinCT
BlinCTМамыр 5, 2024, 5:46 Т.Ж.
Написать свой GraphsView Всем привет. В Qt есть давольно старый обьект дял работы с графиками ChartsView и есть в 6.7 новый но очень сырой и со слабым функционалом GraphsView. По этой причине я хочу написать х…
Evgenii Legotckoi
Evgenii LegotckoiМамыр 2, 2024, 2:07 Т.Қ.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.

Бізді әлеуметтік желілерде бақылаңыз