std::function
右辺値参照からのコンストラクターを提供します。標準で移動された関数オブジェクトはどうなりますか?空になっているので、もう一度呼び出しても効果はありませんか?
4 に答える
この質問にはあまりにも多くの混乱があります。私は物事を明確にレイアウトしようとしています...
このセクションでは、stdで定義されたオブジェクトの移動元の状態について説明します。
17.6.5.15 [lib.types.movedfrom]
C ++標準ライブラリで定義されている型のオブジェクトは、(12.8)から移動できます。移動操作は、明示的に指定することも、暗黙的に生成することもできます。特に明記されていない限り、そのような移動元のオブジェクトは、有効であるが指定されていない状態に置かれるものとします。
これは何を意味するのでしょうか?これは、stdで定義されたmoved-fromオブジェクトが与えられた場合、そのオブジェクトの状態に関する事前の知識を必要としない、そのオブジェクトで何でもできることを意味します。現在の状態の事前知識を必要としないアクションのクラスは、前提条件がないアクションです。
たとえば、に前提条件がないためclear()
、moved-fromを呼び出すことができます。ただし、前提条件があるため、呼び出すことはできません。vector
vector::clear()
pop_back()
の呼び出し演算子を具体的に見てfunction
ください:
20.8.11.2.4 [func.wrap.func.inv]
R operator()(ArgTypes... args) const
効果:INVOKE(f、std :: forward(args)...、R)(20.8.2)、ここでfは* thisのターゲットオブジェクト(20.8.1)です。
戻り値:Rがvoidの場合は何もありません。それ以外の場合は、INVOKE(f、std :: forward(args)...、R)の戻り値です。
スロー:bad_function_call if!* this; それ以外の場合は、ラップされた呼び出し可能オブジェクトによってスローされた例外。
前提条件またはRequires句がないことに注意してください。つまりfunction
、moved-fromのcall演算子を呼び出すことfunction
は、未定義の動作ではありません。がどのような状態であってfunction
も、この呼び出しで前提条件に違反することはありません。
いかなる場合でも、呼び出しが効果を持たないと仕様が述べていないことに注意してください。したがって、効果がない可能性はありません。
呼び出しは、ラップされた関数を呼び出すか、をスローしbad_function_call
ます。これらは2つの選択肢だけです。また、どの動作をするかは、function
オブジェクトの状態によって異なります。また、function
オブジェクトの状態は指定されていません([lib.types.movedfrom])。
20.8.11.2.1p6では、値が指定されていない有効な状態のままになりfunction(function &&f)
ます。f
空の状態は有効な状態であるため、moved-from関数オブジェクトが空になる可能性があることを期待する必要があります。
型消去を実行し、関数オブジェクトは任意にコストがかかる可能性があるためfunction
、移動元オブジェクトを空のままにする最適化は理にかなっています。
std::function<void()> g{std::bind{f, std::array<int, 1000>{}}};
std::function<void()> h{std::move{g}};
h
からの移動によって構築された後g
、含まれているものがコピーではなくからにbind
転送されたと予想されるため、空のままになります。g
h
g
次のプログラムの場合、gcc4.5.1は次のように出力しempty
ます。
#include <functional>
#include <iostream>
void f() {}
int main() {
std::function<void()> g{f}, h{std::move(g)};
std::cout << (g ? "not empty\n" : "empty\n");
}
これは必ずしも最適な動作ではありません。小さな呼び出し可能オブジェクト(関数ポインターなど)をインライン化すると、呼び出し可能オブジェクトを移動して移動元オブジェクトを空にするよりも効率的にコピーできる状況が作成されるため、別の実装ではg
空でない呼び出し可能状態のままになる可能性があります。
標準で移動された関数オブジェクトはどうなりますか?
有効な状態になりますが(したがって、オブジェクトを使用できます)、実際の状態は指定されていません。最後の部分は、オブジェクトが特定の状態にあることを必要とする関数の呼び出しが必ずしも機能しないことを意味します。
空になっているので、もう一度呼び出しても効果はありませんか?
あなたはそれがそうなると仮定することはできません。関数を呼び出すには、実際に呼び出す関数が必要です。それはその状態の一部です。また、状態が指定されていないため、それを呼び出した結果は指定されていません。
オブジェクトを再び意味のある方法で使用する場合は、新しいオブジェクトを作成してfunction
割り当てます。
function<...> old;
function<...> new_ = std::move(old);
old = function<...>(...); //Reset to known state.
old(...); //Call is well-defined.
[func.wrap.func.con]:
function(function&& f);
template <class A> function(allocator_arg_t, const A& a, function&& f);
効果:!fの場合、*これにはターゲットがありません。それ以外の場合、move-fのターゲットを* thisのターゲットに構築し、fを指定されていない値の有効な状態のままにします。