std::move 与复制省略

And*_*ndy 7 c++ visual-studio

以下代码在 Visual Studio 2019 msvc x64 中编译时不会出现警告:

class ThreadRunner {
public:
    void start() {
        m_thread = std::move(std::thread(&ThreadRunner::runInThread, this));
    }
    
private:
    void runInThread() {
        for (int i = 0; i < 1000 * 1000; i++) {
            std::cout << "i: " << i << "\n";
        }
    };
    std::thread m_thread;
};
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用 x64-Clang 编译相同的代码,我会收到以下警告:

warning : moving a temporary object prevents copy elision [-Wpessimizing-move]
Run Code Online (Sandbox Code Playgroud)

这是否意味着我应该写:

m_thread = std::thread(&ThreadRunner::runInThread, this);
Run Code Online (Sandbox Code Playgroud)

反而?编译器会优化掉(“复制删除”)临时变量吗?

msvc x64也会复制删除临时变量吗?

我做了一个实验:

struct B {
    void f1() {
        a = A(5);
    }
    void f2() {
        A tmp = A(5);
        a = tmp;
    }
    void f3() {
        a = std::move(A(5));
    }
    void f4() {
        A tmp = A(5); 
        a = std::move(tmp);  
    }
    A a;
};
Run Code Online (Sandbox Code Playgroud)

f1、f3 和 f4 产生对 A 成员函数的相同调用序列:

default ctor
ctor
move = operator
Run Code Online (Sandbox Code Playgroud)

f2 产生另一个结果:

default ctor
ctor
= operator
Run Code Online (Sandbox Code Playgroud)

eer*_*ika 8

这是否意味着我应该写:

m_thread = std::thread(&ThreadRunner::runInThread, this);
Run Code Online (Sandbox Code Playgroud)

反而?

是的,这就是这个意思,而且你应该这样做。std::thread(&ThreadRunner::runInThread, this)是纯右值,将其转换为 xvalue 不会带来任何好处。


use*_*522 4

两个版本

m_thread = std::thread(&ThreadRunner::runInThread, this);
Run Code Online (Sandbox Code Playgroud)

m_thread = std::move(std::thread(&ThreadRunner::runInThread, this));
Run Code Online (Sandbox Code Playgroud)

行为相同。在任何一种情况下都不可能进行省略,因为这是对 的赋值,而不是对 的初始化m_thread。必须构造临时对象,然后在任一版本中都会对其进行移动分配。

不过,提示仍然是正确的,因为std::move在临时情况下,要么根本没有任何效果(如此处),要么在复制省略被允许/强制的上下文中使用时会阻止省略,例如,如果这是初始化程序m_thread而不是对其进行赋值。

  • @Andy这不是一个优化。移动赋值只是一种在 C++11 之前不存在的语言构造。在 C++11 之前,赋值始终调用复制赋值运算符。但正如我提到的,复制“std::thread”没有任何意义(如何复制线程?)。`std::thread` 在 C++11 之前也不存在。 (2认同)