如果纯右值作为右值引用从函数返回,它会不会突然具有“身份”?
是的,实际上。标准几乎直截了当地说:
[conv.rval]
T 类型的纯右值可以转换为T 类型的 xvalue。此转换通过评估以临时对象作为其结果对象的纯右值,从纯右值初始化 T 类型的临时对象 ([class.temporary]),并生成一个表示临时对象的 xvalue。
这个临时对象,虽然存在,但肯定有“身份”。当然,这种转换的结果不再是纯右值,所以也许我们不应该说纯右值“得到一个身份”。请注意,这也有效,也是因为临时实现:
(int&&)1; // This is different from f(), though, because that reference is dangling but I believe this one isn't (lifetime extension of a temporary by binding to a reference applies here but is suppressed for a return)
请注意,return 语句的操作数和实际返回的内容不必是相同的内容。你给一个int prvalue,你需要一个int xvalue,return 通过实现一个临时值使它工作。它没有义务因为不匹配而失败。不幸的是,当return 语句结束时,该临时值立即被销毁,使 xvalue 悬空,但是,在返回的引用被绑定和临时被销毁之间的那一刻,是的,右值引用确实引用了一个带有它的对象自己的身份。
实现纯右值的其他示例,以便您可以将引用绑定到它们:
int &&x = 1; // acts just like int x = 1 except for decltype and similar considerations
int const &y = 1; // ditto but const and also available in older C++ versions
// in some imaginary API
void install_controller(std::unique_ptr<controller> &&new_controller) {
if(can_replace_controller()) current_controller = std::move(new_controller);
}
install_controller(std::make_unique<controller>("My Controller"));
// prvalue returned by std::make_unique materializes a temporary, binds to new_controller
// might be moved from, might not; in latter case new pointer (and thus object)
// is destroyed at full-expression end (at the semicolon after the function call)
// useful to take by reference so you can do something like
auto p = std::make_unique<controller>("Perseverant Controller");
while(p) { wait_for_something(); install_controller(std::move(p)); }
return 的其他例子不是微不足道的:
double d(int x) { return x; }
// int lvalue given to return but double prvalue actually returned! the horror!
struct dangerous {
dangerous(int x) { launch_missiles(); }
};
dangerous f() { return 1; }
// launch_missiles is called from within the return!
std::vector<std::string> init_data() {
return {5, "Hello!"};
}
// now the operand of return isn't even a value/expression!
// also, in terms of temporaries, "Hello!" (char const[7] lvalue) decays to a
// char const* prvalue, converts to a std::string prvalue (initializing the
// parameter of std::string's constructor), and then that prvalue materializes
// into a temporary so that it can bind to the std::string const& parameter of
// std::vector<std::string>'s constructor