Наприклад, усі ми знаємо, що C++ не ініціалізує змінні, і тому там може опинитися сміття, прочитавши яке можна піти за чужими адресами абощо. Ну, вгадайте шо? Більше ні! Точніше так, але є «але».
void foo() {
int d; // не ініціалізуємо
bar(d); // хоба! — не UB
}Раніше цей код призводив до так званої невизначеної поведінки (UB — undefined behavior), а нині вона вельми визначена: відтепер це нова категорія — помилкова поведінка (erroneous behavior). Утім це не значить, що ваші змінні почнуть раптом занулятися чи робити щось притомне. Натомість змінна отримає «невизначений» стан (такий собі
undefined, який не можна перевірити). Стандарт ніби не описує, що саме там має бути, тож усі компілятори робитимуть на свій розсуд. Але тепер вони принаймні зобовʼязані написати помилку при спробі це значення використати (не обовʼязково під час компіляції — може бути і в рантаймі).А якщо дуже-дуже хочеться повернути UB, то можна використати новий атрибут 😆
void foo() {
int d [[indeterminate]];
bar(d); // Фух, старий-добрий UB :)
}З інших приколів: прибрали порівняння масивів. Раніше можна було писати так:
int arr1[5];
int arr2[5];
bool same = arr1 == arr2; // тепер помилка
Не те щоб хтось дійсно таке писав, окрім джунів на співбесідах. Та й компілятори на це скаржилися з 2019 року. Але новачків це все одно плутає, бо
arr1 та arr2 — це просто вказівники на початок масивів, і такий код порівнює їхні адреси, а не вміст. Добре, що позбулися.Хоча знов-таки… Якщо дуже хочеться, то можна повернути стару поведінку, наприклад, через хак з приведенням типу до звичайного вказівника унарним плюсом 😅
int arr1[5];
int arr2[5];
bool same = arr1 == +arr2; // працює
Отже, C++ стає дедалі суворішою мовою стосовно таких дрібниць, що в більшості випадків є хибним кодом, і водночас не позбавляє свободи. Може в цьому й полягає секрет, чого вона так довго тримається на плаву?