web-dev-qa-db-fra.com

Quels sont les signes d'initialisation des croisements?

Considérons le code suivant:

#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 plaint crosses initialization of 'int r'. Mes questions sont:

  1. Quel est crosses initialization?
  2. Pourquoi le premier initialiseur x + y passe la compilation, mais la dernière a échoué?
  3. Quels sont les problèmes de soi-disant crosses initialization?

ÉDITER :
Je sais que je devrais utiliser des crochets pour spécifier la portée de r, mais je veux savoir pourquoi, par exemple, pourquoi un non-POD ne peut pas être défini dans une instruction de commutation à plusieurs cas.

Merci.

80
Jichao

La version avec int r = x + y; ne compilera pas non plus.

Le problème est qu'il est possible que r atteigne la portée sans que son initialiseur ne soit exécuté. Le code se compilerait bien si vous supprimiez complètement l’initialiseur (c’est-à-dire que la ligne se lirait int r;).

La meilleure chose à faire est de limiter la portée de la variable. De cette façon, vous satisferez à la fois le compilateur et le lecteur.

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

La norme dit (6.7/3):

Il est possible de transférer dans un bloc, mais pas de manière à contourner les déclarations avec initialisation. Un programme qui saute d'un point où une variable locale avec une durée de stockage automatique n'est pas dans la portée à un point où elle est dans la portée est mal formé, sauf si la variable a le type POD (3.9) et est déclarée sans initialiseur (8.5).

93
avakar

Vous devriez mettre le contenu de case entre parenthèses pour lui donner la portée, de cette façon vous pouvez déclarer des variables locales à l'intérieur:

switch(i) {
    case 1:
        {
            // int r = x + y; -- OK
            int r = 1; // Failed to Compile
            cout << r;
        }
        break;
    case 2:
        ...
        break;
};
35
Péter Török

Il est possible de transférer dans un bloc, mais pas de manière à contourner les déclarations avec initialisation. Un programme qui saute d'un point où une variable locale avec une durée de stockage automatique n'est pas dans la portée à un point où elle est dans la portée est mal formé, sauf si la variable a le type POD et est déclarée sans initialiseur.

[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]

Le transfert de la condition d'une instruction switch à une étiquette de cas est considéré comme un saut à cet égard.

3
Ashish Yadav

Je vous suggère de promouvoir votre variable r avant l'instruction switch. Si vous souhaitez utiliser une variable dans les blocs case (ou le même nom de variable mais des utilisations différentes), définissez-la avant l'instruction 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;
    };
}

L'un des avantages est que le compilateur n'a pas à effectuer d'allocation locale (a.k.a. En poussant sur la pile) dans chaque bloc case.

Un inconvénient de cette approche est que les cas "tombent" dans d’autres cas (c’est-à-dire sans utiliser break), car la variable aura une valeur antérieure.

0
Thomas Matthews