在 C ++ 11 中,通常的做法是通过引用将左值传递给函数。
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;
}
为什么不能或为什么不可能?
答案 0 :(得分:5)
这是可能的,但通常是不明智的。这段代码没问题:
#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
很容易。
至于它起作用的原因 - 这里发生的所有事情都是从右值引用到左值引用的隐式转换。如果不允许这样做会很不方便,因为这意味着你不能写:
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 ++标准不只是假设程序员知道它们是什么的一个地方干嘛但我认为历史上它背后的原因是你有能够对一个临时的const引用,以便运算符重载工作。你不必能够指向临时的指针,C禁止它,因为在C中,整数文字永远不需要有一个内存位置。所以C ++继续禁止它,即使在C ++中你确实引用了一个整数文字,那么编译器可能会被迫创建一个包含该值的实际位置。 Stroustrup可能可以对于获取指向整数文字的指针也是如此,但没有必要。
答案 1 :(得分:1)
如果您拥有所有权,则您对该对象负责。如果你不把它保存在某个地方,就像返回临时的引用;当函数范围结束时,您“拥有”的对象将被销毁,因此返回的引用将不再有效。