以下代码在 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)
这是否意味着我应该写:
Run Code Online (Sandbox Code Playgroud)m_thread = std::thread(&ThreadRunner::runInThread, this);反而?
是的,这就是这个意思,而且你应该这样做。std::thread(&ThreadRunner::runInThread, this)是纯右值,将其转换为 xvalue 不会带来任何好处。
两个版本
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而不是对其进行赋值。