Care sunt semnele de inițializare a crucilor? (Programare, C++, Inițializare)

Jichao a intrebat.

Luați în considerare următorul cod:

#include <iostream>
using namespace std;

int main()
{
    int x, y, i;
    cin >> x >> y >> i;
    switch(i) {
        case 1:
            // int r = x + y; -- OK
            int r = 1; // Failed to Compile
            cout << r;
            break;
        case 2:
            r = x - y;
            cout << r;
            break;
    };
}

G++ se plânge crosses initialization of 'int r'. Întrebările mele sunt:

  1. Ce este crosses initialization?
  2. De ce primul inițializator x + y trece de compilare, dar al doilea a eșuat?
  3. Care sunt problemele așa-numitei crosses initialization?

Știu că ar trebui să folosesc paranteze pentru a specifica domeniul de aplicare al r, , dar vreau să știu de ce, de exemplu, de ce non-POD nu a putut fi definit într-o instrucțiune switch cu mai multe cazuri.

Comentarii

  • Înțelegerea mea, având în vedere răspunsurile de mai jos, pentru punctul 3 este că această eroare este o restricție excesivă a c++. Dacă nu se folosește r după label, nu există niciun impact (chiar dacă exemplul de aici folosește r, acesta poate fi eliminat în cazul 2 și compilatorul ar da aceeași eroare). Dovada mai bună este că este permisă în C, și chiar în C11. –  > Por calandoa.
  • Posibil duplicat al Error: Salt la eticheta cazului –  > Por Ciro Santilli新疆棉花TRUMP BAN BAD.
4 răspunsuri
avakar

Versiunea cu int r = x + y; nu va compila nici ea.

Problema este că este posibil ca r să intre în scope fără ca inițializatorul său să fie executat. Codul ar fi compilat bine dacă ați fi eliminat complet inițializatorul (adică linia ar fi fost redată astfel int r;).

Cel mai bun lucru pe care îl puteți face este să limitați domeniul de cuprindere al variabilei. În acest fel, veți satisface atât compilatorul, cât și cititorul.

switch(i)
{
case 1:
    {
        int r = 1;
        cout << r;
    }
    break;
case 2:
    {
        int r = x - y;
        cout << r;
    }
    break;
};

Standardul spune (6.7/3):

Este posibil transferul într-un bloc, dar nu într-un mod care să ocolească declarațiile cu inițializare. Un program care sare de la un punct în care o variabilă locală cu durată de stocare automată nu se află în domeniul de aplicare la un punct în care se află în domeniul de aplicare nu este bine format, cu excepția cazului în care variabila are tipul POD (3.9) și este declarată fără inițializator (8.5).

Comentarii

  • Dar G++ permite int r = x + y. –  > Por Jichao.
  • Ei bine, G++ al meu nu permite. Verificați din nou sau actualizați compilatorul. –  > Por avakar.
  • mulțumesc, mi-a fost de ajutor. Cred că compilatorul C nici măcar nu permite ca declarația să vină după unele coduri. Se pare că C99 permite totuși acest lucru… stackoverflow.com/questions/7859424/…. –  > Por m-ric.
Péter Török

Ar trebui să puneți conținutul fișierului case între paranteze pentru a-i da domeniu de aplicare, în acest fel poți declara variabile locale în interiorul lui:

switch(i) {
    case 1:
        {
            // int r = x + y; -- OK
            int r = 1; // Failed to Compile
            cout << r;
        }
        break;
    case 2:
        ...
        break;
};

Ashish Yadav

Este posibil să se transfere într-un bloc, dar nu într-un mod care să ocolească declarațiile cu inițializare. Un program care sare de la un punct în care o variabilă locală cu durată de stocare automată nu se află în domeniul de aplicare la un punct în care se află în domeniul de aplicare este neformat, cu excepția cazului în care variabila are tipul POD și este declarată fără inițializator.

[Example: Code:

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
}

--end example]

Transferul de la condiția unei instrucțiuni switch la o etichetă case este considerat un salt în acest sens.

Comentarii

  • Bine ați venit la Stack Overflow. Ar trebui să furnizați surse pentru citatele dvs., acesta este C++03:6.7/3. De asemenea, se întâmplă să fie același paragraf pe care l-am citat în răspunsul meu. –  > Por avakar.
Thomas Matthews

Vă sugerez să vă promovați r înaintea variabilei switch declarație. Dacă doriți să folosiți o variabilă peste case blocuri, (sau același nume de variabilă, dar cu utilizări diferite), definiți-o înainte de instrucțiunea switch:

#include <iostream>
using namespace std;

int main()
{
    int x, y, i;
    cin >> x >> y >> i;
// Define the variable before the switch.
    int r;
    switch(i) {
        case 1:
            r = x + y
            cout << r;
            break;
        case 2:
            r = x - y;
            cout << r;
            break;
    };
}

Unul dintre avantaje este că compilatorul nu trebuie să efectueze alocarea locală. (a.k.a. împingerea în stivă). în fiecare case bloc.

Un dezavantaj al acestei abordări este atunci când cazurile se „încadrează” în alte cazuri (adică fără a utiliza break), deoarece variabila va avea o valoare anterioară.

Comentarii

  • Aș sugera să procedați invers. Compilatorul nu trebuie să efectueze o „alocare locală” în ambele cazuri (și în practică nu o va face). –  > Por avakar.