TL; DR
Єдиний спосіб, коли ви можете оголосити змінну за допомогою intializer або якогось нетривіального об'єкта всередині корпусу, - це ввести область блоку за допомогою {}
або іншої керуючої структури, яка має власну область, як цикл, або оператор if .
Деталі Горі
Ми можемо бачити, що випадки - це просто мічені заяви, такі як мітки, що використовуються з оператором goto ( це розглянуто в проекті стандартного проекту C ++, розділ 6.1. Повідомлення із міткою ), і з 6.7
пункту 3 розділу ми бачимо, що стрибок проходження декларації у багатьох випадках заборонений , у тому числі з ініціалізацією:
Можна перенести в блок, але не таким чином, що обходить декларації з ініціалізацією. Програма, яка стрибає 87 з точки, коли змінна з автоматичною тривалістю зберігання не входить до області, до якої вона знаходиться в області дії, неправильно формується, якщо змінна не має скалярного типу, класового типу з тривіальним конструктором за замовчуванням і тривіальним деструктором, версію одного з цих типів, кваліфіковану cv, або масив одного з попередніх типів і оголошується без ініціалізатора (8.5).
і надає цей приклад:
void f() {
// ...
goto lx; // ill-formed: jump into scope of a
ly:
X a = 1;
// ...
lx:
goto ly; // OK, jump implies destructor
// call for a followed by construction
// again immediately following label ly
}
Зверніть увагу, тут є деякі тонкощі, вам дозволяється пропустити повне скалярне оголошення , яке не має ініціалізації, наприклад:
switch( n )
{
int x ;
//int x = 10 ;
case 0:
x = 0 ;
break;
case 1:
x = 1 ;
break;
default:
x = 100 ;
break ;
}
цілком дійсний ( живий приклад ). Звичайно, якщо ви хочете оголосити одну і ту ж змінну у кожному випадку, то для кожного з них потрібен власний обсяг, але це працює так само, як і поза операторами переключення , тому це не повинно бути великим сюрпризом.
Що стосується обґрунтування заборони перейти через ініціалізацію, звіт про дефекти 467, хоча висвітлює дещо іншу проблему, забезпечує розумний випадок для автоматичних змінних :
[...] автоматичні змінні, якщо явно не ініціалізовані, можуть мати невизначені ("сміття") значення, включаючи представлення пасток, [...]
Напевно, цікавіше подивитися на випадок, коли ви розширюєте сферу дії в межах переключення на кілька випадків, найвідоміші приклади цього - це, мабуть , пристрій Даффа, який виглядав би приблизно так:
void send( int *to, const int *from, int count)
{
int n = (count + 7) / 8;
switch(count % 8)
{
case 0: do { *to = *from++; // <- Scope start
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while(--n > 0); // <- Scope end
}
}