gpt4 book ai didi

c++ - std::thread 为什么对象被复制了两次?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:31:46 27 4
gpt4 key购买 nike

为什么在下面的示例代码中,对象被复制了两次?根据线程类的文档构造函数将所有参数复制到线程本地存储,因此我们有理由进行第一个复制。第二呢?

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();
}

上面的输出:

[C]
[COPY]
[COPY]
[~D]
#
[~D]
[~D]

编辑:是的,在添加移动构造函数之后:

A(A && src) {cout << "[MOVE]" << endl;}

输出是这样的:

[C]
[COPY]
[MOVE]
[~D]
#
[~D]
[~D]

最佳答案

对于任何你想移动或避免复制的东西,更喜欢移动构造函数和std::move

但为什么这不会自动发生在我身上?

C++ 中的移动是保守的。它通常只有在您显式编写 std::move() 时才会移动。这样做是因为移动语义如果扩展到非常明确的情况之外,可能会破坏旧代码。出于这个原因,自动移动通常仅限于非常谨慎的情况。

为了避免在这种情况下发生复制,您需要使用 std::move(a) 移动 a(即使将其传递给 std::thread).它第一次制作拷贝的原因是因为 std::thread 不能保证在您完成构造 std::thread 之后该值将存在(并且您没有明确地将其移入)。因此,它会做一些安全的事情并制作一个拷贝(不会引用/指针指向您传入的内容并存储它:代码不知道您是否会让它保持事件状态)。

同时拥有移动构造函数和使用 std::move 将允许编译器最大程度且高效地移动您的结构。如果您使用的是 VC++(无论是否使用 CTP),则必须显式编写移动构造函数,否则 MSVC 将(甚至有时会错误地)声明并使用复制构造函数。

关于c++ - std::thread 为什么对象被复制了两次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15990689/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com