为什么右值对象不会移动到带有右值参数的函数?

Why does rvalue object does not get moved to function with rvalue parameter?

我想知道为什么 std::move 到具有右值参数的函数实际上并没有移动任何东西,而是通过引用传递?

特别是当我知道它适用于构造函数时。

我是运行下面的代码:

#include <memory>
#include <iostream>

void consume_ptr(std::shared_ptr<int> && ptr) {
    std::cout << "Consumed " << (void*) ptr.get() << std::endl;
}

int main(int argc, char ** argv)
{
    std::shared_ptr<int> ptr = std::make_shared<int>();
    consume_ptr(std::move(ptr));
    if (ptr) {
        std::cout << "ptr should be moved?" << std::endl;
    }
    return 0;
}

输出为:

ptr should be moved?

根据我读过的所有内容,std::shared_ptr 应该已经在函数内部移动,这意味着对象 ptr 本身在将其移动到 [= 之后将保持 nullptr 16=],但事实并非如此!

我尝试使用我的一些自定义 class 日志记录,看起来移动构造函数从未被调用过。 它在每个编译器和优化级别下都是可重现的。

谁能帮我解决这个问题?

std::move 本身实际上并没有移动任何东西。也就是说,单独 std::move 不会调用任何移动构造函数或移动赋值运算符。根据 cppreference.

,它实际上所做的是有效地将其参数转换为右值,就好像 static_cast<typename std::remove_reference<T>::type&&>(t) 一样

为了使任何移动真正发生,移动的对象必须分配给或用于其他对象的移动初始化。例如,它可以用来初始化一个成员。

void something::consume_ptr(std::shared_ptr<int> && ptr) {
    this->ptr = std::move(ptr);
    std::cout << "Consumed " << (void*) ptr.get() << std::endl;
}

但是,让您的指针在不被分配给任何东西的情况下移动的一种方法是简单地按值传递它,从而使您的指针移动到参数中。

void consume_ptr(std::shared_ptr<int> ptr) {
    std::cout << "Consumed " << (void*) ptr.get() << std::endl;
}

如果您最终要将参数分配给某物,这种方式实际上比右值方式更有用,因为它也允许您通过复制传递内容,而不仅仅是通过移动。

void consume_ptr_by_rvalue(std::shared_ptr<int> && ptr);
void consume_ptr_by_value(std::shared_ptr<int> ptr);

void do_stuff() {
    std::shared_ptr<int> x = /*...*/;
    std::shared_ptr<int> y = /*...*/;

    // consume_ptr_by_rvalue(x); // Doesn't work
    consume_ptr_by_rvalue(std::move(y)); // Risk of use-after-move

    std::shared_ptr<int> z = /*...*/;
    std::shared_ptr<int> w = /*...*/;

    consume_ptr_by_value(z);
    consume_ptr_by_value(std::move(w)); // Still risk, but you get the idea
    consume_ptr_by_value(make_shared_ptr_to_something()); // Can directly pass result of something
}

这里:

void consume_ptr( std::shared_ptr<int>&& ptr )
{
    std::shared_ptr<int> new_ptr { ptr }; // calling copy ctor

    std::cout << "Consumed " << ( void* ) new_ptr.get( ) << '\n';
}

那里没有移动。不调用移动构造函数或移动赋值运算符。这只是右值引用的简单传递。

输出:

Consumed 0x20d77ebe6a0
ptr should be moved?

现在看看这个:

void consume_ptr( std::shared_ptr<int>&& ptr )
{
    std::shared_ptr<int> new_ptr { std::move(ptr) }; // calling move ctor

    std::cout << "Consumed " << ( void* ) new_ptr.get( ) << '\n';
}

int main( )
{
    std::shared_ptr<int> ptr { std::make_shared<int>( ) };
    consume_ptr( std::move(ptr) );

    if ( ptr )
    {
        std::cout << "ptr should be moved?" << std::endl;
    }
}

输出:

Consumed 0x21160bbdf40

看看。移动操作发生了。而 if 的 body 没有 运行.