Почему вы можете вернуть функцию по ссылке для локальной переменной, а не для временной переменной? C ++ - PullRequest
5 голосов
/ 06 марта 2012

например, эта функция f определена так:

int f(int x){return x;}

как вы знаете Вы не можете назначить ссылку на этот временный int:

int& rf=f(2);// this will give an error

но если я переопределю свою функцию f следующим образом:

int& f(int x){return x;}
f(2);// so now f(2) is a reference of x, which has been destroyed 

поэтому мой вопрос: как компилятор может не позволить вам создать ссылку на временный файл, который будет уничтожен после проверки (в первом случае). а с другой стороны, он позволяет вам создать ссылку f (2) на x, в то время как компилятор знает, что эта ссылка будет уничтожена после return.

Ответы [ 6 ]

7 голосов
/ 06 марта 2012

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

int & f()
{
    int x;
    extern int & g(int & x);

    // Does this return a reference to "x"?
    // The compiler has no way to tell.
    return g(x);
}

Даже без вызова внешних функций все еще может быть сложно проанализировать сложный программный поток, чтобы определить, является ли возвращенная ссылка локальной;вместо того, чтобы пытаться определить то, что считается «достаточно простым» для диагностики, стандарт не требует диагностики - он просто заявляет, что дает неопределенное поведение.Хороший компилятор должен выдавать предупреждение, по крайней мере, в простых случаях.

Привязка временного к неконстантной ссылке - это то, что компилятор может легко обнаружить, и поэтому стандарт требует диагностики для этого.

1 голос
/ 06 марта 2012

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

Чтобы отклонить вторую, компилятор может применить правило, чтоreturn оператор функции, которая возвращается по ссылке, не может быть именем автоматической переменной (включая параметр функции по значению).Это тоже кажется мне довольно простым правилом.

Я не знаю, почему в стандарте не указано, что это неправильно.Я не могу думать о каком-либо действительном использовании для него, но, возможно, во время первого стандарта это создало бы чрезмерную нагрузку на ту или иную реализацию.Или, может быть, чувствовалось, что это только половина исправления, и его не стоит беспокоить (есть множество других способов создать висячую ссылку, это просто блокирует один из них).

Причина, по которой стандарт не делаетв общем, остановите создание неконстантной ссылки, привязанной к временной, в тех случаях, когда это нормально.Например:

struct Foo {
    static void set(Foo &f) { f.val = 0; }
    int val;
    int bar() {
        set(*this);
        return val;
    }
};

std::cout << Foo().bar() << "\n";

Здесь Foo() является временным, и строка set(*this) связывает его с неконстантной ссылкой (но не напрямую, она использует выражение lvalue *this, которое относится квременные несколько раз, но не другие).Здесь нет проблем, временные ссылки отживают.Поэтому для языка было бы излишне ограничительным каким-либо образом предотвращать привязку любого временного к какой-либо неконстантной ссылке.

1 голос
/ 06 марта 2012

Вы можете привязать временное значение r к значению const, чтобы продлить срок его службы.

const int& rf=f(2); 
1 голос
/ 06 марта 2012

Поскольку, как указано в стандарте, возвращение ссылки на временную переменную из функции является неопределенным поведением.

Что на самом деле не так, так это определение функции:

int& f(int x)
{
   return x;
}
0 голосов
/ 06 марта 2012

Проблема в том, что семантически нет разницы между переменной в стеке или переменной в куче и т. Д. - поэтому у языка нет другого выбора, кроме как разрешить это, даже если это неопределенное поведение. В первом примере вы получаете легкую ошибку компиляции, потому что вы пытаетесь связать ссылку на временную переменную, которая может быть запрещена языком.

0 голосов
/ 06 марта 2012

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

в противном случае ожидается неопределенное поведение.

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

...