C++11 移动到本地 const 引用:作用域

C++11 move to local const reference: scope

对于常规的局部常量引用变量,作用域是prolonged。这就是以下代码按预期工作的原因:

#include <iostream>
#include <memory>

struct foo
{
        foo()
        {
                std::cout << "foo() @" << (void*)this << std::endl;
        }
        ~foo()
        {
                std::cout << "~foo() @" << (void*)this << std::endl;
        }
};

int main()
{
        auto const& f = std::make_shared<foo>();
        std::cout << "f = " << f.get() << std::endl;
        return 0;
}

// prints:
// foo() @0x55f249c58e80
// f = 0x55f249c58e80
// ~foo() @0x55f249c58e80

似乎在使用 std::move():

分配移动的对象时,这并没有像预期的那样工作
#include <iostream>
#include <memory>
#include <list>

struct foo
{
        foo()
        {
                std::cout << "foo() @" << (void*)this << std::endl;
        }
        ~foo()
        {
                std::cout << "~foo() @" << (void*)this << std::endl;
        }
};

int main()
{
        std::list<std::shared_ptr<foo>> l;
        l.push_back(std::make_shared<foo>());
        auto const& f = std::move(l.front());
        l.clear();
        std::cout << "f = " << f.get() << std::endl;
        return 0;
}

// prints
// foo() @0x564edb58fe80
// ~foo() @0x564edb58fe80
// f = 0x564edb58fe80

std::move() 确实改变了范围,还是我在处理编译器错误?

将变量从 auto const& f 更改为 auto f 可以解决问题。如果我将移动包装到另一个函数中,它也有效:

auto const& f = [&]() { return std::move(l.front()); }();

这几乎就像 std::move() 不共享与函数调用相同的语义,而是好像它只是一个常规变量赋值:

auto const& f = std::move(l.front());

让我们搁置std::move()并创建这个函数:

struct sometype {};

const sometype &foobar( const sometype &cref ) { return cref; }

现在我们使用它:

const sometype &ref = foobar( sometype() );

你怎么看,这种情况下临时文件的生命周期会延长吗?不,不会。仅当您直接 分配给引用时,生命周期才会延长。当它通过一个函数或通过 static_caststd::move 时,延长就消失了。所以你和 std::move()

有完全相同的问题
struct sometype {
    sometype() { std::cout << "ctype()" << std::endl; }
    ~sometype() { std::cout << "~ctype()" << std::endl; }
};

const sometype &foobar( const sometype &cref ) { return cref; }

int main()
{
    const sometype &cref1 = foobar( sometype() );
    sometype &&cref2 = std::move( sometype() );
    std::cout << "main continues" << std::endl;
}

输出:

ctype()
~ctype()
ctype()
~ctype()
main continues     

live example

注意:你不应该在 return 语句中使用 std::move(),它不会给你任何东西。

为了您的代码更改。您应该记住 std::move() 不会移动任何东西。它由特殊的赋值运算符或构造函数(如果它们提供了类型)完成。所以当你写这段代码时:

const type &ref = std::move( something );

不涉及构造函数和赋值运算符,因此不会发生移动。要进行实际移动,您必须将其分配给一个变量:

type val = std::move( something );

现在如果可能的话会搬家,否则就复制。