Обнаружение компилятором возврата ссылки на локальную переменную

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

Мы знаем, что это зло, и, как правило, компилятор печатает 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] подходит, потому что стандарт указывает, что время жизни переменной, привязанной к ссылке на константу, должно быть увеличено, чтобы соответствовать времени жизни ссылки на константу.

Строка [2] тоже вроде в порядке...

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

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


person Matthieu M.    schedule 15.09.2010    source источник
comment
В конце концов возможно, что get_env_value() возвращает ссылку на переменную, которая не выходит за пределы области видимости, например глобальную, и в этом случае все должно быть в порядке.   -  person UncleBens    schedule 15.09.2010
comment
@UncleBens: это хороший момент   -  person Chubsdad    schedule 15.09.2010
comment
@UncleBens: get_env_value возвращается по копии, как это может быть ссылкой на переменную в глобальной области видимости?   -  person Matthieu M.    schedule 15.09.2010
comment
@Konrad: да, довольно противно. Хуже всего, я думаю, то, что без get_env_value подписи все кажется правильным.   -  person Matthieu M.    schedule 15.09.2010


Ответы (2)


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

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

person jalf    schedule 15.09.2010
comment
Можно ли настроить lint, чтобы отловить это? - person Steve Townsend; 15.09.2010
comment
Я согласен, что компиляция достаточно медленная, компилятор предупреждает об отсутствии возврата и возвращении ссылки на локальные переменные, хотя я почему-то ожидал, что phase вызовет предупреждение:/ - person Matthieu M.; 15.09.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 — «Выход из конца функции эквивалентен возврату без значения; это приводит к неопределенному поведению в функции, возвращающей значение».

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

person Chubsdad    schedule 15.09.2010
comment
@Chusbad: большинство компиляторов предупреждают о функциях без возврата (иногда оскорбительно, но только в крайних случаях). Я действительно не ожидал ошибки... но предупреждение было бы очень приятно :) - person Matthieu M.; 15.09.2010