我有一些类似这样的代码
struct A
{
int i;
A(int i) : i(i) {}
~A()
{
cout << "destroy " << i << endl;
}
};
using p = shared_ptr<A>;
p f(int i)
{
return make_shared<A>(i);
}
int main()
{
auto i = f(1);
cout << "a" << endl;
p && j = f(2);
cout << "a" << endl;
p && k = move(f(3));
cout << "a" << endl;
auto l = move(f(4));
cout << "a" << endl;
p ptr = make_shared<A>(5);
auto && a = move(ptr);
cout << "a" << endl;
}
输出为
a
a
destroy 3
a
a
a
destroy 5
destroy 4
destroy 2
destroy 1
我不明白为什么move
函数返回右值引用的返回值会导致破坏。但是直接将其放在右值引用中是可以的。
实际上是在std::get<>
中的std::tuple
中发现了问题。我有一个函数,返回两个shared_ptr的元组,并使用std :: get <>访问该元素。但是我发现auto && i = get<0>(f())
会导致错误,而auto i = get<0>(f())
不会。然后我发现std :: move
答案 0 :(得分:2)
让我们一一讲解
auto i = f(1); // (1)
这将创建一个局部变量i
(不是引用),其初始值为f(1)
。还行吧。 i
的生存期一直到块结束。
p && j = f(2); // (2)
这将使用对j
返回的对象的引用来初始化引用f(2)
,并延长了f(2)
返回的值的寿命,因此可以。 j
的生存期一直到块结束。
p && k = move(f(3)); // (3)
这将使用对move
返回的对象的引用来初始化该引用,由于move
返回的值是对f(2)
返回的临时对象的引用,因此不会延长生存期。 (不是临时对象),但{strong> f(2)
返回的临时变量在初始化k
之后就死了,因为它的生命周期没有延长(未分配给引用变量),并且{{ 1}}最终成为悬而未决的参考。
k
与(1)一样,此举是无用的。 auto l = move(f(4)); // (4)
的生存期一直到块结束。
l
这是局部变量初始化。 p ptr = make_shared<A>(5); // (5)
的生存期一直到块结束。
ptr
auto && a = move(ptr);
是对a
的引用。这不会更改ptr
的生存期。
答案 1 :(得分:2)
p && j = f(2);
此处,f
返回类型为std::shared_ptr<A>
的prvalue。当您将引用绑定到prvalue时,它将把prvalue的生存期延长为引用的生存期。这意味着f
返回的对象的生存期与j
相同。
p && k = move(f(3));
在这里,f
再次返回prvalue。 std::move
的参数绑定到该prvalue,将其生存期扩展为参数的生存期 。 std::move
不会返回prvalue。它返回一个xvalue。生存期扩展名不适用于xvalues,因此f
的参数生存期结束后,由std::move
返回的对象将被销毁。也就是说,它在std::move
返回时被销毁。 k
然后成为悬空参考。
答案 2 :(得分:1)
由于使用std::move
,您已将返回值转换为引用。而不是const引用,因此是临时的。
因此不会进行复制,并且在行结束时,返回值将被破坏。