5

私は実験し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;
}

結果は次のとおりです。

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

次に、次のように変更しようとしvoid foo(obj a)ましたvoid foo(obj &a)

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

この単純なコードに対してオブジェクトのコピーが 5 つ作成されるのはなぜですか? 私は認めざるを得ません、私は本当に混乱しています。誰かがこれを説明してくれませんか?

編集

私はVS2012を使用しています

4

2 に答える 2

7

あなたの場合、objコピーされています:

  1. への呼び出しで 2 回std::async
  2. Twice byasyncの への内部呼び出しstd::bind
  3. void foo(obj a)値で受け取るため、 への呼び出しで 1 回a

信じられないかもしれませんが、実際には VC10 以降、コピー数が減少しています

ライブラリ (標準ライブラリであろうと別のライブラリであろうと) が、型に対して予想するよりも多くのコピーをトリガーすることは、まったく珍しいことではありません。そして通常、それについてできることはあまりありません。

コピーを防止するために人々が一般的に行っていることが 2 つあります。

  1. 参照で取得objします(または、あなたの場合、 const ref since foodoes not modify obj)。これにはstd::refasync を使用する必要があります。
  2. のムーブ コンストラクタを定義しobjます。これにより、一時オブジェクトの作成と破棄が妨げられることはありませんが、プロセスを少し最適化する機会が得られます。

1 つだけを保持するオブジェクトの単純な例で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);
    auto future = async(foo, std::cref(a));
    future.wait();

    return 0;
}

移動コンストラクターを定義する例:

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

    /* ... */
};
于 2013-02-16T17:27:37.430 に答える
2

aバインド フェーズ中にコピーされます。a の複数のコピーを回避するには、move constructorセマンティクスを使用します。

move ctorにを追加obj:

class obj {
public:
    ...
    obj(obj&& other) {
        cout << "move obj" << endl;
        val = std::move(other.val);
    }
};

主に:

    obj a(5);
    auto future = async(foo, std::move(a));
    ...

このように、obj の 5 つのインスタンスが引き続き作成されますが、async はmovableオブジェクトをサポートするため、同じコピーがインスタンスからインスタンスに移動されます (重いオブジェクトの場合、これはオブジェクトをコピーするよりも重要です)。したがって、出力は次のようになります。

new obj
move obj
move obj
move obj
move obj
delete obj
delete obj
delete obj
5
delete obj
delete obj
于 2013-02-16T16:42:45.310 に答える