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 Т.Ж.

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

Пікірлер

Тек рұқсаты бар пайдаланушылар ғана пікір қалдыра алады.
Кіріңіз немесе Тіркеліңіз
OI
  • Ora Iro
  • Жел. 24, 2024, 6:38 Т.Ж.

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

  • Нәтиже:40ұпай,
  • Бағалау ұпайлары-8
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:50ұпай,
  • Бағалау ұпайлары-4
m
  • molni99
  • Қаз. 26, 2024, 1:37 Т.Ж.

C++ - Тест 004. Указатели, Массивы и Циклы

  • Нәтиже:80ұпай,
  • Бағалау ұпайлары4
Соңғы пікірлер
ИМ
Игорь МаксимовҚар. 22, 2024, 11:51 Т.Ж.
Django - Оқулық 017. Теңшелген Django кіру беті Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii LegotckoiҚаз. 31, 2024, 2:37 Т.Қ.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZEҚаз. 19, 2024, 8:19 Т.Ж.
Qt Creator көмегімен fb3 файл оқу құралы Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь МаксимовҚаз. 5, 2024, 7:51 Т.Ж.
Django - Сабақ 064. Python Markdown кеңейтімін қалай жазуға болады Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas5Шілде 5, 2024, 11:02 Т.Ж.
QML - Сабақ 016. SQLite деректер қоры және онымен QML Qt-та жұмыс істеу Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Енді форумда талқылаңыз
Evgenii Legotckoi
Evgenii LegotckoiМаусым 24, 2024, 3:11 Т.Қ.
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey1Қар. 15, 2024, 6:04 Т.Ж.
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProjectМаусым 4, 2022, 3:49 Т.Ж.
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9AnonimҚаз. 25, 2024, 9:10 Т.Ж.
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

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