51

私は以下を試しました:

std::function<void ()> getAction(std::unique_ptr<MyClass> &&psomething){
    //The caller given ownership of psomething
    return [psomething](){ 
        psomething->do_some_thing();
        //psomething is expected to be released after this point
    };
}

しかし、それはコンパイルされません。何か案は?

アップデート:

提案されているように、所有権をラムダに譲渡する必要があることを明示的に指定するには、いくつかの新しい構文が必要です。現在、次の構文について考えています。

std::function<void ()> getAction(std::unique_ptr<MyClass> psomething){
    //The caller given ownership of psomething
    return [auto psomething=move(psomething)](){ 
        psomething->do_some_thing();
        //psomething is expected to be released after this point
    };
}

それは良い候補になるでしょうか?

更新1:

次のように、の実装を示しmoveますcopy

template<typename T>
T copy(const T &t) {
    return t;
}

//process lvalue references
template<typename T>
T move(T &t) {
    return std::move(t);
}

class A{/*...*/};

void test(A &&a);

int main(int, char **){
    A a;
    test(copy(a));    //OK, copied
    test(move(a));    //OK, moved
    test(A());        //OK, temporary object
    test(copy(A()));  //OK, copying temporary object
    //You can disable this behavior by letting copy accepts T &  
    //test(move(A())); You should never move a temporary object
    //It is not good to have a rvalue version of move.
    //test(a); forbidden, you have to say weather you want to copy or move
    //from a lvalue reference.
}
4

5 に答える 5

74

この問題は、C++14のラムダ一般化キャプチャによって対処されます。

// a unique_ptr is move-only
auto u = make_unique<some_type>(some, parameters); 

// move the unique_ptr into the lambda
go.run([u = move(u)]{do_something_with(u);});
于 2013-06-06T17:28:59.137 に答える
42

unique_ptrをラムダで永続的にキャプチャすることはできません。実際、ラムダ内の何かを永続的にキャプチャする場合は、コピー可能である必要があります。単に可動では不十分です。

unique_ptrこれはC++11の欠陥と見なされる可能性がありますが、値をラムダに移動したいことを明示的に示すための構文が必要になります。C ++ 11仕様は、名前付き変数での暗黙的な移動を防ぐために非常に注意深く表現されています。それが存在する理由std::moveであり、これは良いことです。

必要なことを行うには、を使用するかstd::bind(半複雑になり、短いシーケンスが必要になりますbinds)、または通常の古いオブジェクトを返す必要があります。

また、実際にそのmoveコンストラクターを作成しているのでない限り、決して取っunique_ptrてはいけません。&&値でそれを取るだけです。ユーザーが値で提供できる唯一の方法は、を使用することstd::moveです。実際、&&moveコンストラクター/代入演算子を作成している(または転送関数を実装している)場合を除いて、一般的には何も取得しないことをお勧めします。

于 2011-11-23T03:48:26.050 に答える
19

Nicol Bolasが述べたように使用する「半畳み込み」ソリューションstd::bindは、結局のところそれほど悪くはありません。

std::function<void ()> getAction(std::unique_ptr<MyClass>&& psomething)
{
    return std::bind([] (std::unique_ptr<MyClass>& p) { p->do_some_thing(); },
                     std::move(psomething));
}
于 2012-10-05T10:54:03.357 に答える
16

私にとってうまくいった次善の解決策は、unique_ptrをaに変換してから、ラムダでshared_ptrキャプチャすることでした。shared_ptr

std::function<void()> getAction(std::unique_ptr<MyClass> psomething)
{
    //The caller given ownership of psomething
    std::shared_ptr<MyClass> psomethingShared = std::shared_ptr<MyClass>(std::move(psomething));
    return [psomethingShared]()
    {
        psomethingShared->do_some_thing();
    };
}
于 2015-01-13T16:15:45.333 に答える
3

私はこの本当に危険な回避策を使用しました。これには、unique_ptr内部を貼り付けることが含まれshared_ptrます。これは、私のコードがunique_ptr(APIの制限のために)必要だったため、実際にコードをに変換できなかったためですshared_ptr(そうしないと、元にunique_ptr戻すことができませんでした)。

この忌まわしきものを使用することの私の正当化は、それが私のテストコードのためであり、テスト関数呼び出しに参加しなければならなかったstd::bindということです。unique_ptr

// Put unique_ptr inside a shared_ptr
auto sh = std::make_shared<std::unique_ptr<Type>>(std::move(unique));

std::function<void()> fnTest = std::bind([this, sh, input, output]() {
    // Move unique_ptr back out of shared_ptr
    auto unique = std::move(*sh.get());

    // Make sure unique_ptr is still valid
    assert(unique);

    // Move unique_ptr over to final function while calling it
    this->run_test(std::move(unique), input, output);
});

これで、呼び出しはにを渡している間fnTest()に呼び出します。2回目の呼び出しでは、最初の呼び出し中にがすでに移動/失われているため、アサーションが失敗します。run_test()unique_ptrfnTest()unique_ptr

于 2015-04-02T10:05:49.787 に答える