Evgenii Legotckoi
Evgenii Legotckoi05 червня 2017 р. 03: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 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
  • 05 червня 2017 р. 04:55

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

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
AD

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

  • Результат:50бали,
  • Рейтинг балів-4
m
  • molni99
  • 26 жовтня 2024 р. 01:37

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

  • Результат:80бали,
  • Рейтинг балів4
m
  • molni99
  • 26 жовтня 2024 р. 01:29

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

  • Результат:20бали,
  • Рейтинг балів-10
Останні коментарі
ИМ
Игорь Максимов22 листопада 2024 р. 11:51
Django - Підручник 017. Налаштуйте сторінку входу до Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
Evgenii Legotckoi
Evgenii Legotckoi31 жовтня 2024 р. 14:37
Django - Урок 064. Як написати розширення для Python Markdown Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
A
ALO1ZE19 жовтня 2024 р. 08:19
Читалка файлів fb3 на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
ИМ
Игорь Максимов05 жовтня 2024 р. 07:51
Django - Урок 064. Як написати розширення для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas505 липня 2024 р. 11:02
QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
Тепер обговоріть на форумі
Evgenii Legotckoi
Evgenii Legotckoi24 червня 2024 р. 15:11
добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
t
tonypeachey115 листопада 2024 р. 06:04
google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
NSProject
NSProject04 червня 2022 р. 03:49
Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
9
9Anonim25 жовтня 2024 р. 09:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

Слідкуйте за нами в соціальних мережах