Evgenii Legotckoi
Evgenii Legotckoi5. Juni 2017 03:33

C++ - Tutorial 003. Konstanten

Inhalt

C++ unterstützt zwei Unveränderlichkeitsnotationen:

  1. const – was impliziert, dass sich der Wert nicht ändert. Es wird hauptsächlich verwendet, um Schnittstellen für Daten zu spezifizieren, die an Funktionen und Methoden übergeben werden, ohne Angst haben zu müssen, geändert zu werden. Der Compiler verfolgt das Vorhandensein des const-Bezeichners;
  2. constexp - was die Berechnung einer Konstante zur Kompilierzeit impliziert. Wird verwendet, um Daten im Speicher abzulegen, wo sie nicht beschädigt werden, und um die Leistung zu verbessern.

Zum Beispiel:

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) не является константным выражением.

Damit eine Funktion in einem konstanten Ausdruck verwendet, also vom Compiler ausgewertet werden kann, muss sie mit dem Bezeichner constexpr definiert werden.

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

Die constexpr -Funktion muss einfach genug sein, um vom Compiler ausgewertet zu werden und auch den berechneten Wert zurückzugeben. constexpr-Funktionen können mit nicht konstanten Argumenten in Kontexten aufgerufen werden, die keine konstanten Ausdrücke erfordern.

Konst

Objekte mit dem Bezeichner const können nicht geändert werden und müssen ebenfalls initialisiert werden.

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

Da Objekte mit const -Bezeichnern nicht geändert werden können, ist der folgende Code fehlerhaft:

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

Beachten Sie, dass const den Typ des Objekts ändert, kein Hinweis darauf, wie die Variable zugewiesen werden soll. const schränkt ein, wie ein Objekt manipuliert werden kann.

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

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

Bei der Verwendung eines Zeigers sind zwei Objekte beteiligt: der Zeiger selbst und das Objekt, auf das er zeigt. Wenn Sie einer Zeigerdeklaration const voranstellen, wird das Objekt konstant, nicht der Zeiger. Um einen Zeiger selbst und nicht das Objekt, auf das er zeigt, als const zu deklarieren, platzieren Sie const nach dem Zeigerzeichen. Zum Beispiel:

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;                   // Ошибка: указатель является константой
}

Die Position von const relativ zum Basistyp ist nicht kritisch, da es keinen Datentyp const* gibt. Die Position von const relativ zum Symbol * ist grundlegend. Daher sind folgende Eingaben möglich:

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

Ein Objekt, das konstant ist, wenn auf es über einen einzelnen Zeiger zugegriffen wird, kann veränderlich sein, wenn auf andere Weise darauf zugegriffen wird. Dies ist besonders nützlich für Funktionsargumente. Indem ein Zeigerargument als const deklariert wird, wird die Funktion daran gehindert, das Objekt zu ändern, auf das sie zeigt. Zum Beispiel:

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

Die erste Variante wird für Strings verwendet, deren Elemente von der Funktion nicht verändert werden sollen und gibt einen Zeiger auf const zurück, der eine Veränderung des Ergebnisses nicht zulässt. Die zweite Version wird für veränderliche Zeichenfolgen verwendet.

Sie können einem Zeiger auf eine Konstante die Adresse einer nicht konstanten Variablen zuweisen, denn das kann nicht schaden. Die Adresse einer Konstanten kann jedoch keinem Nicht-Konstanten-Zeiger zugewiesen werden, da dies den Wert des Objekts ändern würde. Zum Beispiel:

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

Ein konstanter Ausdruck ist ein Ausdruck, der zur Kompilierzeit ausgewertet wird. Konstante Ausdrücke können keine Werte und Variablen verwenden, die zur Kompilierzeit nicht bekannt sind.

Es gibt viele Gründe, warum jemand eine benannte Konstante anstelle eines in einer Variablen gespeicherten Buchstabens oder Werts haben möchte:

  1. Benannte Konstanten erleichtern das Verständnis und die Wartung von Code.
  2. Eine Variable kann geändert werden (daher müssen wir bei unserer Argumentation vorsichtiger sein als bei einer Konstanten).
  3. Die Sprache erfordert konstante Ausdrücke für Array-Größen, Case-Labels und Template-Wert-Argumente.
  4. Eingebettete Programmierer legen gerne unveränderliche Daten in einen Nur-Lese-Speicher. Denn Nur-Lese-Speicher ist billiger als dynamischer Speicher (in Bezug auf Kosten und Stromverbrauch) und oft reichlicher vorhanden. Darüber hinaus sind Daten im permanenten Speicher vor den meisten Systemausfällen geschützt.
  5. Wenn die Initialisierung zur Kompilierzeit durchgeführt wird, dann kann es in einem mehrsträngigen Programmsystem keine Datenabweichungen geben.
  6. Das Durchführen von Berechnungen in der Kompilierungsphase verbessert die Programmleistung.

Der constexpr-Wert wird zur Kompilierzeit ausgewertet, und wenn er nicht ausgewertet werden kann, gibt der Compiler einen Fehler aus.

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
    // ...
}

Die Möglichkeiten konstanter Ausdrücke sind ziemlich groß, da es möglich ist, ganzzahlige Datentypen, Gleitkommadaten, Aufzählungen sowie Operatoren zu verwenden, die die Werte von Variablen nicht ändern (wie +, ? und [] , aber nicht = oder ++ * )

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
Stabiles Hosting des sozialen Netzwerks EVILEG. Wir empfehlen VDS-Hosting für Django-Projekte.

Magst du es? In sozialen Netzwerken teilen!

BlinCT
  • 5. Juni 2017 04:55

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

Kommentare

Nur autorisierte Benutzer können Kommentare posten.
Bitte Anmelden oder Registrieren
Letzte Kommentare
ИМ
Игорь Максимов5. Oktober 2024 07:51
Django – Lektion 064. So schreiben Sie eine Python-Markdown-Erweiterung Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
d
dblas55. Juli 2024 11:02
QML - Lektion 016. SQLite-Datenbank und das Arbeiten damit in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
k
kmssr8. Februar 2024 18:43
Qt Linux - Lektion 001. Autorun Qt-Anwendung unter Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
Qt WinAPI - Lektion 007. Arbeiten mit ICMP-Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25. Dezember 2023 10:30
Boost - statisches Verknüpfen im CMake-Projekt unter Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
Jetzt im Forum diskutieren
J
JacobFib17. Oktober 2024 03:27
добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
JW
Jhon Wick1. Oktober 2024 15:52
Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
КГ
Кирилл Гусарев27. September 2024 09:09
Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
F
Fynjy22. Juli 2024 04:15
при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

Folgen Sie uns in sozialen Netzwerken