std :: thread为什么将对象复制两次? [英] std::thread Why object is copied twice?

查看:141
本文介绍了std :: thread为什么将对象复制两次?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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为什么将对象复制两次?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆