2015-09-15 7 views
3
#include <iostream> 

int getID (int k) { 
    static int& r = k; 
    return r++; 
} 

int main() 
{ 
    int a = getID (10); 
    int b = getID (10); 
    std::cout << "a = " << a << ", b = " << b << std::endl; 
    return 0; 
} 

Я не понимаю, почему этот код компилируется.Статическая ссылка со ссылкой на временную переменную

  1. Как можно использовать статическую ссылку для ссылки на локальную переменную k, которая исчезнет в конце вызова функции).
  2. Во втором вызове мы повторно инициализируем статическую ссылку с новой переменной . Пожалуйста, объясните, что здесь происходит, почему статические REFERENCE могут быть «переопределены» (я думаю, что я не понимаю значение ссылки на статическую переменную внутри метода).

ответ

5
  1. язык не препятствует связыванию ссылки на объекты ограниченной продолжительности жизни. Это очень затрудняет использование ссылок.

    (Это не мешает вам от связывания ссылок на временных. Но параметр функции является L-значение, как локальным переменным, так что это разрешено.)

    Но, если вы пишете код, где ссылка привязывается к объекту, который он переживает, и вы продолжаете использовать ссылку, вы получаете неопределенное поведение, не требуется диагностика и, скорее всего, segfault. Это по существу то же самое, что и болтающийся указатель в C.

  2. Во втором звонке вы делаете не перетащите статическую ссылочную переменную в новую временную. Статическая переменная инициализируется только раз, первая время вызывается функцией. Эта строка эффективно пропускается во всех последующих вызовах.

Если вы хотите язык, который будет ловить ошибки, как это для вас, и убедитесь, что вы не получите укусили оборванные ссылки, вы можете посмотреть на ржавчине. У компилятора ржавчины есть «программа проверки займа», которая проверяет ваши ссылки для вас, не налагая накладные расходы во время выполнения, как многие известные языки, собранные с помощью мусора. Однако у Rust нет статических переменных, поэтому нет прямого перевода этого кода;)

В C++ я полагаю, что вышеупомянутая ошибка, скорее всего, была бы уловлена ​​инструментом статического анализа, таким как Coverity, который проведет некоторые проверки продолжительности жизни в вашем когда он сканирует его. Но компилятор C++ не сделает это за вас, вам нужно будет использовать сторонний инструмент.

3

Как можно использовать статическую ссылку для ссылки на локальную переменную k, которая исчезнет в конце вызова функции).

Это вполне возможно. Вы просто заканчиваете болтаться ссылкой, что приводит к неопределенному поведению. Но здесь не значительная часть static.

Во втором вызове мы повторно инициализируем статическую ссылку новой переменной. [...]

Нет, у нас его нет. A static переменная инициализируется только один раз. Итак, второй раз в getID(), мы все еще имеем в виду предыдущие временные k.Что мы тогда увеличиваем, что является неопределенным поведением. Одним из аспектов «неопределенного поведения» является «код, который выглядит так, как будто он работает».

Рассмотрим новый тип:

struct WrappedInt { 
    ~WrappedInt() { 
     i = 0; 
    } 

    int i; 
}; 

и переписать код, чтобы использовать его вместо:

int getID (WrappedInt k) { 
    static WrappedInt& r = k; 
    return r.i++; 
} 

Здесь мы видим, что после того, как временное выходит из области видимости, и он явно обнулит (с нашей болтливой ссылкой), мы вернемся 0:

int main() 
{ 
    int a = getID (WrappedInt{10}); // a == 10 
    int b = getID (WrappedInt{10}); // b == 0 
    std::cout << "a = " << a << ", b = " << b << std::endl; 
    return 0; 
} 
Смежные вопросы