std ::异步和对象复制 [英] std::async and object copy

查看:110
本文介绍了std ::异步和对象复制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试 std :: async ,结果是一个类似如下的代码:

  class obj {
public:
int val;

obj(int a):val(a){
cout< new obj< endl;
}
〜obj(){
cout<< delete obj< endl;
}
};


void foo(obj a){

this_thread :: sleep_for(chrono :: milliseconds(500));
cout<< a.val< endl;
}

int main(int argc,int ** args){

obj a(5);
auto future = async(foo,a);
future.wait();

return 0;
}

,结果是:


$ b b

  new obj 
delete obj
delete obj
delete obj
5
delete obj
delete obj
delete obj

然后我尝试更改 void foo a) void foo(obj& a)

  new obj 
delete obj
delete obj
delete obj
5
delete obj
delete obj

为什么要为这个简单的代码创建我的对象的5个副本?
我不得不承认,我真的很困惑。



我使用的是VS2012

解决方案

在您的情况下,正在复制 obj


  1. 调用 std :: async

  2. 两次 async 调用 std :: bind

  3. 一旦通过调用 void foo(obj a),因为它需要 a .microsoft.com / VisualStudio / feedback / details / 649268 / std-bind-and-std-function-generate-a-crazy-number-of-copy>自VC10后减少。



    看到一个库(不管是标准库还是另一个库)比你想要的类型多出几个拷贝,并不是很常见。



    通常,人们通常会做两件事来防止复制:


    1. 通过引用获取 obj (或者在您的情况下,从 foo 不会修改 obj )。这需要使用 std :: ref with async。

    2. 定义移动 obj 的构造函数。这不会阻止临时构建和销毁,但它会给您一个优化过程的机会。

    注意在你只有一个 int 的对象的实例中,它可能实际上比复制而不是移动或通过引用传递更快。






    通过引用将 obj 传递给 async

      void foo(const obj& a){
    this_thread: :sleep_for(chrono :: milliseconds(500));
    cout<< a.val< endl;
    }

    int main(int argc,int ** args){
    obj a(5);
    self future = async(foo,std :: cref(a));
    future.wait();

    return 0;
    }






    定义移动构造函数

      class obj 
    {
    public:
    / * ... * /

    obj(obj& a):val(move(a.val)){
    //以更快捕获使用移动后的bug。
    a.val = 0;
    }

    / * ... * /
    };


    I was experimenting with std::async and ended up with a code that looks like that :

    class obj {
    public:
        int val;
    
        obj(int a) : val(a) {
            cout << "new obj" << endl;
        }
        ~obj() {
            cout << "delete obj" << endl;
        }
    };
    
    
    void foo(obj a) {
    
        this_thread::sleep_for(chrono::milliseconds(500));
        cout << a.val << endl;
    }
    
    int main(int argc, int **args) {
    
        obj a(5);
        auto future = async(foo, a);
        future.wait();
    
        return 0;
    }
    

    and the result is :

    new obj
    delete obj
    delete obj
    delete obj
    5
    delete obj
    delete obj
    delete obj
    

    I then tried to change void foo(obj a) by void foo(obj &a) :

    new obj
    delete obj
    delete obj
    delete obj
    5
    delete obj
    delete obj
    

    Why would 5 copies of my object be made for this simple code? I have to admit, I'm really confused. Would someone care to explain this?

    Edit

    I'm using VS2012

    解决方案

    In your case, obj is being copied:

    1. Twice by the call to std::async.
    2. Twice by async's internal call to std::bind.
    3. Once by the call to void foo(obj a) since it takes a by value.

    Believe it or not, the number of copies has actually been reduced since VC10.

    It is not at all uncommon to see a library (be it the standard library or another one) trigger a few more copies than you would expect on your types. And usually, there is not too much you can do about it in.

    There are 2 things that people commonly do to prevent copies:

    1. Take obj by reference (or in your case, const ref since foo does not modify obj). This will require using std::ref with async.
    2. Define a move constructor for obj. This won't prevent temporaries from being constructed and destroyed, but it will give you a chance to optimize the process a bit.

    Note that in your bare example of an object that holds onto only one int, it might actually be faster to copy rather than move or pass by reference.


    Example for passing obj by reference into async:

    void foo(const obj& a) {
        this_thread::sleep_for(chrono::milliseconds(500));
        cout << a.val << endl;
    }
    
    int main(int argc, int **args) {
        obj a(5);
        auto future = async(foo, std::cref(a));
        future.wait();
    
        return 0;
    }
    


    Example for defining a move constructor:

    class obj
    {
    public:
        /* ... */
    
        obj(obj&& a) : val(move(a.val)) {
            // It is good practice to 0 out the moved object to catch use-after-move bugs sooner.
            a.val = 0;
        }
    
        /* ... */
    };
    

    这篇关于std ::异步和对象复制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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