C ++ 11 — Вернуть rvalue, переданное в функцию lvalue?

В C ++ 11, обычной практикой является передача lvalue в функцию по ссылке.

int& f(int& a){
return a;
}

int main(void){
auto a = 1;
auto b = f(a);
return 0;
}

Однако возможно ли передать значение в функцию по ссылке rvalue и вернуть это значение через lvalue?

int& f(int&& a){
return a;
}

int main(void){
auto b = f(1);
return 0;
}

Почему это или почему это невозможно?

2

Решение

Это возможно, но обычно неразумно. Этот код в порядке:

#include <utility>
#include <iostream>

int &foo(int &&a) {
return a;
}

int main() {
int a = 1;
std::cout << foo(std::move(a)) << "\n";
}

Этот код тоже в порядке:

int main() {
std::cout << foo(1) << "\n";
}

Этот код имеет неопределенное поведение:

int main() {
int &a = foo(1); // lifetime of the temporary 1 ends "at the semi-colon"std::cout << a << "\n";
}

Таким образом, довольно легко неправильно использовать функцию foo,

Что касается причины, по которой это работает — все, что здесь происходит, это неявное преобразование из ссылки на rvalue в ссылку на lvalue. Было бы неудобно, если бы это не было разрешено, потому что это означало бы, например, что вы не можете написать:

void bar1(const int &a) {
std::cout << (a + 1) << "\n";
}

void bar2(int &&a) {
bar1(a);
... do destructive stuff with a ...
}

Могут быть более веские причины для разрешения неявного преобразования. Я не знаю официальной мотивации, это только первое, о чем я подумал.

Даже в C ++ 03 была связанная проблема. Ты можешь написать:

const int *baz(const int &a) { return &a; }

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

Вы могли бы сказать, что запрещающий &1 (взятие указателя на литерал или другое временное значение) — это то место, в котором стандарт C ++ не просто предположим, что программист знает, что они делают. Но я думаю, что исторически обоснование этого заключается в том, что вы иметь чтобы иметь возможность получить постоянную ссылку на временную переменную, чтобы перегрузка оператора работала. Вы не должны иметь возможность взять указатель на временный объект, и C запрещает это, потому что в C целочисленный литерал никогда не должен иметь место в памяти. Таким образом, C ++ продолжает запрещать это, хотя в C ++, когда вы берете ссылку на целочисленный литерал, компилятор может быть вынужден создать фактическое местоположение, содержащее это значение. Страуструп наверное мог сказали то же самое о получении указателя на целочисленный литерал, но в этом не было необходимости.

5

Другие решения

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

1

По вопросам рекламы [email protected]