问题描述
为什么在下面的示例代码中,对象被复制了两次?根据文档的构造方法,线程类会将所有参数复制到线程本地存储中,因此我们有理由进行第一次复制。那第二呢?
Why in the example code below, object is copied twice? According documentation constructor of thread class copies all arguments to thread-local storage so we have reason for the first copy. What about second?
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]
编辑:
是的,在添加move构造函数之后:
Well yes, after adding move constructor:
A(A && src) {cout << "[MOVE]" << endl;}
输出如下:
[C]
[COPY]
[MOVE]
[~D]
#
[~D]
[~D]
推荐答案
想移动或避免复制,更喜欢移动构造函数和 std :: move
。
For anything you want to move or avoid copies, prefer move constructors and std::move
.
但是为什么
在C ++中移动是保守的。通常,只有在您明确编写 std :: move()
时,它才会移动。这样做是因为移动语义(如果扩展到非常明确的环境之外)可能会破坏旧代码。因此,自动移动通常仅限于非常谨慎的情况。
Move in C++ is conservative. It generally will only move if you explicitly write std::move()
. This was done because move semantics, if extended beyond very explicit circumstances, might break older code. Automatic-moves are often restricted to very careful set of circumstances for this reason.
为了避免在这种情况下进行复制,您需要移动 a
,方法是使用 std :: move(a)
(即使将其传递到 std :: thread
)。第一次创建副本的原因是因为std :: thread不能保证在完成std :: thread的构造之后(并且您没有明确地将其移入)该值将存在。因此,它会做安全的事并进行复制(不要引用或指向您传入的内容并进行存储:代码不知道您是否将其保存下来)。
In order to avoid copies in this situation, you need to shift a
around by using std::move(a)
(even when passing it into std::thread
). The reason it makes a copy the first time around is because std::thread can't guarantee that the value will exist after you have finished constructing the std::thread (and you haven't explicitly moved it in). Thusly, it will do the safe thing and make a copy (not take a reference/pointer to what you passed in and store it: the code has no idea whether or not you'll keep it alive or not).
同时具有move构造函数和使用 std :: move
可使编译器最大程度地有效移动结构。如果您使用的是VC ++(不带CTP),则必须显式编写move构造函数,否则MSVC会(甚至有时会错误地)声明并使用Copy构造函数。
Having both a move constructor and using std::move
will allow the compiler to maximally and efficiently move your structure. If you're using VC++ (with the CTP or not), you must explicitly write the move constructor, otherwise MSVC will (even sometimes erroneously) declare and use a Copy constructor.
这篇关于std :: thread为什么将对象复制两次?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!