为什么在下面的示例代码中,对象被复制两次?根据线程类的文档构造函数将所有参数复制到线程本地存储,因此我们有理由进行第一次复制.第二个怎么样?
class A {
public:
A() {cout << "[C]" << endl;}
~A() {cout << "[~D]" << endl;}
A(A const& src) {cout << "[COPY]" << endl;}
A& operator=(A const& src) {cout << "[=}" << endl; return *this;}
void operator() () {cout << "#" << endl;}
};
void foo()
{
A a;
thread t{a};
t.join();
}
Run Code Online (Sandbox Code Playgroud)
上面的输出:
[C]
[COPY]
[COPY]
[~D]
#
[~D]
[~D]
Run Code Online (Sandbox Code Playgroud)
编辑:是的,添加移动构造函数后:
A(A && src) {cout << "[MOVE]" << endl;}
Run Code Online (Sandbox Code Playgroud)
输出是这样的:
[C]
[COPY]
[MOVE]
[~D]
#
[~D]
[~D]
Run Code Online (Sandbox Code Playgroud)
小智 5
对于您想要移动或避免复制的任何内容,最好选择移动构造函数和std::move.
但为什么这不会自动发生在我身上呢?
C++ 中的移动是保守的。它通常只有在您明确写入时才会移动std::move()。这样做是因为移动语义如果扩展到非常明确的情况之外,可能会破坏旧代码。由于这个原因,自动移动通常仅限于非常谨慎的情况。
为了避免在这种情况下进行复制,您需要a通过使用进行切换std::move(a)(即使将其传递到std::thread)。它第一次创建副本的原因是因为 std::thread 无法保证在完成 std::thread 的构造之后该值将存在(并且您还没有显式地将其移入)。因此,它将做安全的事情并制作一个副本(不获取对您传入的内容的引用/指针并存储它:代码不知道您是否会使其保持活动状态)。
同时拥有移动构造函数和使用std::move将使编译器能够最大程度地、有效地移动您的结构。如果您使用 VC++(无论是否带有 CTP),则必须显式编写移动构造函数,否则 MSVC 将(甚至有时错误地)声明并使用复制构造函数。
| 归档时间: |
|
| 查看次数: |
1165 次 |
| 最近记录: |