TL; DR
Jedynym sposobem, w jaki można zadeklarować zmienną z intializatorem lub jakimś nietrywialnym obiektem wewnątrz przypadku, jest wprowadzenie zakresu blokowego przy użyciu {}
lub innej struktury kontrolnej, która ma własny zakres, jak pętla lub instrukcja if .
Krwawe szczegóły
Widzimy, że przypadki są po prostu etykietowanymi instrukcjami, takimi jak etykiety używane z instrukcją goto ( jest to omówione w szkicu standardu C ++ w sekcji 6.1 Oznakowane instrukcje ) i widzimy z sekcji 6.7
paragraf 3, że przeskakiwanie do deklaracji jest w wielu przypadkach niedozwolone , w tym te z inicjalizacją:
Możliwe jest przeniesienie do bloku, ale nie w sposób omijający deklaracje przy inicjalizacji. Program, który przeskakuje 87 z punktu, w którym zmienna z automatycznym czasem przechowywania nie znajduje się w zakresie, do punktu, w którym jest w zakresie, jest źle sformułowana, chyba że zmienna ma typ skalarny, typ klasy z trywialnym konstruktorem domyślnym i trywialnym destruktorem, kwalifikowana wersja cv jednego z tych typów lub tablica jednego z powyższych typów i jest zadeklarowana bez inicjatora (8.5).
i podaje ten przykład:
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
}
Zauważ, że są tutaj pewne subtelności, możesz przeskoczyć poza deklarację skalarną , która nie ma inicjalizacji, na przykład:
switch( n )
{
int x ;
//int x = 10 ;
case 0:
x = 0 ;
break;
case 1:
x = 1 ;
break;
default:
x = 100 ;
break ;
}
jest całkowicie poprawny ( przykład na żywo ). Oczywiście, jeśli chcesz zadeklarować tę samą zmienną w każdym przypadku, każda z nich będzie potrzebować własnego zakresu, ale działa to tak samo również poza instrukcjami switch , więc nie powinno to być dużym zaskoczeniem.
Jeśli chodzi o uzasadnienie niedopuszczania do przeskoczenia po inicjalizacji, raport defektu 467, chociaż obejmuje nieco inny problem, zapewnia rozsądny argument dla zmiennych automatycznych :
[...] zmienne automatyczne, jeśli nie są jawnie zainicjowane, mogą mieć nieokreślone („śmieciowe”) wartości, w tym reprezentacje pułapek, [...]
Prawdopodobnie bardziej interesujące jest przyjrzenie się przypadkowi, w którym rozszerza się zakres w ramach przełączania na wiele przypadków, najsłynniejszym tego przykładem jest prawdopodobnie urządzenie Duffa, które wyglądałoby mniej więcej tak:
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
}
}