std::move和临时对象的生命周期

19
这段代码的执行顺序能有人解释一下吗?
struct Foo {
    ~Foo() {
        std::cout << "1";
    }
};

int main() {
    const Foo& bar = Foo();
    const Foo& baz = std::move(Foo());
    std::cout << "2";
}

以下代码打印出121
我明白为什么在2之后得到1,因为对象的生命周期绑定在执行代码块上,我也知道rvalue可以绑定到lvalue const引用,但为什么移动对象的析构函数会立即被调用呢?这是什么原因?这个析构函数具体在哪里被调用?

5
std::move(Foo())(又称为 static_cast<Foo&&>(Foo()))不是临时对象;将const引用绑定到它上面并不能延长其生命周期。一个右值引用和一个右值不是相同的东西。 - molbdnilo
1
令人失望的是,无论是GCC还是Clang都没有直接警告这个问题。它们确实都会警告baz未被使用,但不会抱怨bar,因为销毁具有副作用,这是一个间接的线索,但并不是一个好的解释:( - Matthieu M.
@molbdnilo:它是一个临时对象。没有寿命延长的原因是该引用没有“直接”绑定到临时对象。 - Ben Voigt
2个回答

13
std::move(Foo()); 中,Foo 对象绑定到移动函数的参数,而不是 baz
当函数返回时,临时对象将被销毁。

12

std::move有一个转发引用参数t,它绑定到prvalue Foo()。然后当该函数返回时,该临时对象被销毁,从而产生了上述输出。

本质上,临时对象绑定到参数t而不是baz

//-------------------------------------------------------------------v------------> Foo() is bound to this parameter 
template< class T > constexpr std::remove_reference_t<T>&& move( T&& t ) noexcept;

1
它不是在函数返回时被销毁,而是在初始化表达式执行完成后销毁。 - HolyBlackCat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接