auto&& mytup = std::make_tuple(9,1,"hello");
std::get<0>(mytup) = 42;
cout << std::get<0>(mytup) << endl;
auto&& var =
func()
始终使用auto var = func()
代替{{1}},以便没有复制/移动吗?答案 0 :(得分:14)
在初始化程序是一个返回短寿命右值引用的函数调用的情况下,它只会出现问题。用更少的单词和更多的代码:
// Fine; lifetime extension applies!
auto&& ref = 42;
auto id = [](int&& i) -> int&& { return std::move(i); };
auto&& uhoh = id(42);
// uhoh is now a stale reference; can't touch it!
相比之下,auto uhoh = id(42);
本来可以正常工作。
在您的情况下,因为std::make_tuple
返回值而不是右值引用,所以没有问题。
我认为真正的危险来自具有右值参考参数的那些函数和函数模板,并且返回对某些子对象的rvalue引用,其寿命依赖于那些子对象。 (话虽如此,像auto&& ref = std::move(42);
这样简单的事情就会出现问题!)
C ++ 11的情况并非全新,请考虑:T const& ref = bar(T_factory());
。
答案 1 :(得分:8)
是。从不返回引用类型的函数返回的任何内容都可能涉及复制/移动。这就是RVO的意义所在。您的引用绑定的对象需要以某种方式初始化。
没有。为什么要这样?绑定到引用的临时/ prvalue的生命周期由引用的范围确定。
如果func()没有返回引用类型,则效率(行为)不应有任何差异
之间
auto&& var = func();
和
auto var = func();
在这两种情况下,都会构造一个生命周期到包含块末尾的对象。在一种情况下,它有自己的名称,在另一种情况下,它通过引用命名。在这两种情况下,名称都可以用作左值。在任何一种情况下,RVO都可以同样适用。
有些编译器可能更好地优化本地对象而不是参考,即使在当前情况下,引用临时实际上与本地对象没有什么不同。
如果func()
可能会返回引用,则情况会有很大不同 - 在这种情况下,您必须决定是否要复制/移动。
答案 2 :(得分:0)
评估对make_tuple
的调用的结果是tuple
实例化的prvalue临时值。 auto
类型说明符将被推断为相同的tuple
实例化(7.1.6.4p6),因此mytup
的类型为tuple<...> &&
。然后,通过引用mytup
(12.2p5)对prvalue临时进行生命周期扩展。
make_tuple
内可能仍有RVO。)mytup
将被视为左值,即使其类型是右值引用。然而,使用auto &&
毫无意义,因为所有合理的编译器都会忽略临时复制/移动。澄清一下,将mytup
视为右值的唯一方法是使用std::forward<decltype(mytup)>(mytup)
,如What does auto&& tell us?;但是,如果您知道 mytup
的类型(在这种情况下为tuple<...>
),那么您也可以使用std::move
。
答案 3 :(得分:0)
C ++中有一个特定的规则(甚至在C ++ 11之前),如果你将一个引用绑定到临时,那么临时的生命周期将扩展到引用的生命周期。
更简单的情况是:
int foo () {
return 42;
}
int bar () {
const int& x = foo();
return x; // Here is safe to use x
}