Условная инициализация в коммутаторе

почему этот фрагмент кода работает нормально

void foo(int i)
{
    switch(i) {
    case 1:
    {
        X x1;
        break;
    }
    case 2:
        X x2;
        break;
    }
}

в то время как следующее дает ошибку компиляции (инициализация " x1 "пропускается меткой "case")?

void foo(int i)
{
    switch(i) {
    case 1:
        X x1;
        break;
    case 2:
        X x2;
        break;
    }
}

Я понимаю, что использование фигурных скобок вводит новую область, поэтому хранилище не будет выделено для x1, пока мы не нажмем его открывающую скобку. Но x2 по-прежнему инициализируется внутри метки случая, не заключая фигурные скобки. Не должно ли это быть ошибкой?

Я думаю, что инициализация x2 может быть условно пропущены оба фрагмента кода

5 ответов


1: допустимый

 case 1:
        {
        X x1;
        break;
        }

если он не попадает в условие,x1 не может использоваться никакими дальнейшими утверждениями, поэтому не может быть ошибки во время выполнения с этим. x1 не пытается существовать вне скобок.


2: неверный

 switch(i) {
    case 1:
        X x1; //don't break
        i = 2;
        ...
        ...
        ...
     case 2:
        x1.someOperation()

 }

в приведенном выше, если i был 2 первоначально вы нажмете x1.someOperation() до X x1 который построил бы объект.

если был разрешено компилировать, это приведет к ошибке выполнения или нет, в зависимости от того, является ли случае:1 был выполнен до 2, (и объект был построен). Следовательно, компилятор запрещает его.


то же самое разрешено с обычными старыми типами данных, которые не может есть пользовательский конструктор.


обратите внимание, что вы получите ошибку только тогда, когда X - Это не-Pod. Если X Это POD, тогда вы не получите никакой ошибки (когда вы не используете фигурные скобки).

в случае не-стручка, вы не может пропустить инициализацию переменных, объявленных в той же области. Это приводит к ошибке компиляции, когда вы не используете скобки, потому что switch позволяет пропустить инициализация переменных, но в то же время это сделало их доступными для использования в все case надписи под ним. Это опасно.

подумайте об этом: если i is 2, то управление будет прыгать на второй case напрямую без инициализации x1, и тогда вы сможете использовать x1 во втором случае, даже если он не инициализирован. Это не имеет смысла. Поэтому язык требует, чтобы это была ошибка.


кстати, чтобы узнать, что такое POD и non-POD, см. Эти темы:


общая идея заключается в том, что каждый case не является изолированной областью: код под case 2 может относиться к x1 переменная, так как она была объявлена ранее в той же области (т. е.: весь switch block): Конечно, он не был бы инициализирован, и это привело бы к ошибке.

добавление фигурных скобок вы фактически разделяете каждый caseобласть, позволяющая объявлять переменные в case 1 это не может быть отнесено вне его.


не рекомендуется создавать переменные внутри условных операторов. Я рекомендую вам создать переменную вне switch оператор, а затем asign значения к нему в соответствии с условием на i:

void foo(int i) {

    X x1;

    switch(i) {
        case 1:
            x1 = ...;
            break;
        case 2:
            x1 = ...;
            break;
    }
}

в версии, которая терпит неудачу, объявление x1 не выйдут из области видимости до нескольких строк после case 2: метки. Вот в чем проблема. Заявление x2 нормально, потому что нет case метка между объявлением и концом его области действия.