- Переполнение:
- Беззнаковое - арифметика в
$Z(2^n)$ , где$n$ - битность числа - Знаковое - UB
- Беззнаковое - арифметика в
- Integer promotion:
-
int->long long -
signed->unsigned- это боль, потому что биты знакового типа начитают интерпретироваться как биты беззнакового
-
- Size comparison:
-
char$<=$ short$<=$ int$<=$ long$<=$ long long
-
- Ranges
-
int32_t x: $[$INT32_MIN; INT32_MAX$]$INT32_MAX = 0x7FFFFFFFINT32_MIN = 0x80000000-
INT32_MAX + 1is UB
-
uint32_t x: $[$UINT32_MIN; UINT32_MAX$]$UINT32_MIN = 0x00000000UINT32_MAX = 0xFFFFFFFF-
UINT32_MAX + 1 = 0is OK
-
- Запись чисел в 8- и 16-ти ричных системах счисления
- Префиксы
0и0x int a = 012; // 1*2 + 8 * 1 = 10int b = 0x12; // 1 * 2 + 16 * 1 = 18
- Префиксы
- Sign - 1
- Exponent - 11
- Mantissa - 52
- Model:
IEEE 754 - More info
int foo() {
static int x = 0; // хранится в секции data (см. Memory)
std::cout << ++x;
}- Выполняет преобразования, извесные компилятору
- Note
staticон потому что проверяет возможность конвертации на этапе компиляции - An explicit type conversion operator in C++ that performs conversions between related types, such as implicit conversions, user-defined conversions, and conversions within inheritance hierarchies
int a = 5;
double d = static_cast<double>(a);- Работа с сырой памятью
- Интерпретирует байты памяти одного типа как байты памяти другого типа
- Умеет приводить только указатели и ссылки, поскольку не создает новую сущность
int a = 0;
double* b = reinterpret_cast<double*>(&a);- Навешивание и снятие константности
#include <iostream>
void f(int&) { std::cout << 1; }
void f(const int&) { std::cout << 2; }
int main() {
int a = 10;
f(a); // 1
f(const_cast<const int&>(a)); // 2
f(static_cast<const int&>(a)); // 2
}int a = 10;
const int& b = a;
int& c = const_cast<int&> b; // OKconst int& b = 3;
int& c = const_cast<int&>(b); // очень серьезный UB- По очереди применяет все касты (поэтому юзать не надо)
- Лучше явно писать нужный каст
- В отличие от остальных C++ кастов, C-style-каст можно перегружать
const_caststatic_caststatic_cast + const_castreinterpret_castreinterpret_cast + const_cast
T->[cv] T[&]Derived&->Base&
Any (possibly incomplete) type other than function type or reference type is a type in a group of the following four distinct but related types:
- A cv-unqualified version
- A const-qualified version
- A volatile-qualified version
- A const-volatile-qualified version
When an object is first created, the cv-qualifiers used (which could be part of decl-specifier-seq or part of a declarator in a declaration, or part of type-id in a new-expression) determine the constness or volatility of the object, as follows:
- an object whose type is const-qualified, or
- a non-mutable subobject of a const object.
Such object cannot be modified: attempt to do so directly is a compile-time error, and attempt to do so indirectly (e.g., by modifying the const object through a reference or pointer to non-const type) results in undefined behavior.
- an object whose type is volatile-qualified,
- a subobject of a volatile object, or
- a mutable subobject of a const-volatile object.
Every access (read or write operation, member function call, etc.) made through a glvalue expression of volatile-qualified type is treated as a visible side-effect for the purposes of optimization (that is, within a single thread of execution, volatile accesses cannot be optimized out or reordered with another visible side effect that is sequenced-before or sequenced-after the volatile access. This makes volatile objects suitable for communication with a signal handler, but not with another thread of execution, see std::memory_order). Any attempt to access a volatile object through a glvalue of non-volatile type (e.g. through a reference or pointer to non-volatile type) results in undefined behavior.
- Пишем многопоточную игру, в которой у игрока может быть какое-то количество денег
- Механика сбора денег осуществляется во вторничном потоке, а проверка - в первичном:
size_t money = 0; // изначально денег нет
// ...
// в рамках этого потока не меняем значение money
// ...
if (player_wants_to_buy_a_sword()) {
if (money > 100) { // меч стоит 100 монет
give_sword();
} else {
name_player_as_poor();
}
}- Проблема состоит в том, что компилятор вправе оптимизировать механику и всегда называть игрока бедным
- Решение - навесить
volatile:
volatile size_t money = 0;- an object whose type is const-volatile-qualified,
- a non-mutable subobject of a const volatile object,
- a const subobject of a volatile object, or
- a non-mutable volatile subobject of a const object.
Behaves as both a const object and as a volatile object.
Each cv-qualifier (const and volatile) can appear at most once in any cv-qualifier sequence. For example, const const and volatile const volatile are not valid cv-qualifier sequences.
mutable- permits modification of the class member declared mutable even if the containing object is declared const (i.e., the class member is mutable).
May appear in the declaration of a non-static class members of non-reference non-const type:
class X {
mutable const int* p; // OK
mutable int* const q; // ill-formed
mutable int& r; // ill-formed
};There is partial ordering of cv-qualifiers by the order of increasing restrictions. The type can be said more or less cv-qualified than:
- unqualified < const
- unqualified < volatile
- unqualified < const volatile
- const < const volatile
- volatile < const volatile
References and pointers to cv-qualified types can be implicitly converted to references and pointers to more cv-qualified types.
To convert a reference or a pointer to a cv-qualified type to a reference or pointer to a less cv-qualified type, const_cast must be used.
==TODO== https://en.cppreference.com/w/cpp/language/implicit_cast.html#Qualification_conversions
#include <cstdlib>
int main() {
int n1 = 0; // non-const object
const int n2 = 0; // const object
int const n3 = 0; // const object (same as n2)
volatile int n4 = 0; // volatile object
const struct {
int n1;
mutable int n2;
} x = {0, 0}; // const object with mutable member
n1 = 1; // OK: modifiable object
// n2 = 2; // error: non-modifiable object
n4 = 3; // OK: treated as a side-effect
// x.n1 = 4; // error: member of a const object is const
x.n2 = 4; // OK: mutable member of a const object isn't const
const int& r1 = n1; // reference to const bound to non-const object
// r1 = 2; // error: attempt to modify through reference to const
const_cast<int&>(r1) = 2; // OK: modifies non-const object n1
const int& r2 = n2; // reference to const bound to const object
// r2 = 2; // error: attempt to modify through reference to const
// const_cast<int&>(r2) = 2; // undefined behavior: attempt to modify const object n2
[](...) {}(n3, n4, x, r2); // see also: [[maybe_unused]]
}