2

C++11中,通常的做法是通过引用将左值传递给函数。

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

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

但是,是否可以通过右值引用将值传递给函数并通过左值返回该值?

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

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

为什么会或为什么不可能?

4

2 回答 2

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 可能可以关于获取指向整数文字的指针也说过同样的话,但没有必要。

于 2013-01-31T12:03:20.337 回答
1

如果您拥有所有权,则您应对该对象负责。如果你不把它保存在某个地方,这就像返回一个对临时的引用;当函数范围结束时,您“拥有”的对象被销毁,因此返回的引用不再有效。

于 2013-01-31T12:00:22.193 回答