Обнаружение компилятором возврата ссылки на локальную переменную - PullRequest
5 голосов
/ 15 сентября 2010

Меня только что укусило неприятное неопределенное поведение из-за возврата ссылки на локальную переменную.

Мы знаем, что это зло, и, как правило, компилятор печатает хороший warning, чтобы сказать нам об этом ... хорошо, что gcc (3.4.2), похоже, не слишком далеко продвигает проверки.

std::string get_env_value(std::string const& key);

std::string const& get_phase()
{
  std::string const& phase = get_env_value("PHASE"); // [1]
  std::cout << "get_phase - " << phase << '\n';
  return phase;                                      // [2]
}

Это компилируется без сбоев, и все же мы попадаем в ужасную сферу неопределенного поведения.

Строка [1] в порядке, потому что стандарт определяет, что время жизни переменной, связанной с ссылкой const, должно быть увеличено, чтобы соответствовать времени жизни ссылки const.

Линия [2] тоже вроде бы в порядке ...

  • Охватывают ли спецификации C ++ этот случай?
  • Кто-нибудь знает, обычно ли это диагностируется? (Я могу пропустить флаг или что-то ...)

Мне кажется, что статический анализ должен быть в состоянии сказать, что использование "продления жизни" для [1], [2] небезопасно, но я думаю, что это может быть ужасно быстро ...

Ответы [ 2 ]

5 голосов
/ 15 сентября 2010

Стандарт не распространяется на [2]. Это позволяет привязывать rvalue к ссылке на const, но это не позволяет вам возвращать ссылку на const и иметь время жизни значения rvalue, к которому она привязана.

И действительно, статический анализ может это уловить, но, как всегда, это компромисс. Компиляция C ++ достаточно медленная, поэтому разработчикам компиляторов приходится сопоставлять преимущества дальнейшего статического анализа, который может позволить им производить более качественную диагностику, в сравнении с увеличенным временем компиляции.

2 голосов
/ 15 сентября 2010
  1. Нет, я не думаю, что Стандарт упоминает / охватывает этот конкретный случай.

  2. VS 2010 дает предупреждения компиляции (/ Za, /W4).

Итак, определенно это выглядит как диагностируемое состояние.

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

std::string const& get_phase() 
{ 
    std::string const& phase = get_env_value("PHASE"); // [1] 
    std::cout << "get_phase - " << phase << '\n'; 

    if(1){
        while(1){
            return phase;
        }
    }
    return phase;                                      // [2] 
} 

Теперь VS не сообщает о предупреждении, как раньше.

В качестве примера, на первый взгляд, кажется, что компилятору должно быть легко обнаружить и поймать, что не все пути возвращаютзначение.Но компиляторы (например, VS) этого не делают.

int get_phase() 
{
    char ch;
    if(ch){
        return 0;
    }
     // nothing returned from here.
} 

Итак, я предполагаю, что код в OP, вероятно, имеет те же сложности для диагностики состояния, что и пример, показанный выше, хотя я не уверен.Единственное, что хорошо, это то, что стандарт ясен в этом случае.

$ 6.6.3 / 2 - «Выливание из конца функции эквивалентно возвращению без значения; это приводит к неопределенностиПоведение в функции, возвращающей значениеПожалуйста.Понятно, что возвращенная ссылка указывает на объект, который уже разрушен.Таким образом, доступ к такому объекту приведет к неопределенному поведению

...