C++11 クロージャーについて正しく考える方法とstd::function
、クロージャーの実装方法とメモリの処理方法に関する情報が欲しいです。
私は時期尚早の最適化を信じていませんが、新しいコードを作成する際に、自分の選択がパフォーマンスに与える影響を慎重に検討する習慣があります。また、非決定論的なメモリ割り当て/割り当て解除の一時停止を避ける必要があるマイクロコントローラやオーディオ システムなど、かなりの量のリアルタイム プログラミングも行っています。
したがって、C++ ラムダをいつ使用するか、または使用しないかについて、より理解を深めたいと思います。
私の現在の理解では、キャプチャされたクロージャのないラムダは C コールバックとまったく同じです。ただし、環境が値または参照によってキャプチャされると、匿名オブジェクトがスタック上に作成されます。関数から value-closure を返さなければならないときは、それを でラップしstd::function
ます。この場合、閉鎖記憶はどうなりますか? スタックからヒープにコピーされますか? が解放されるたびに解放されますか。std::function
つまり、 のように参照カウントされstd::shared_ptr
ますか?
リアルタイム システムでは、一連のラムダ関数を設定し、B を継続引数として A に渡し、処理パイプラインA->B
が作成されると想像します。この場合、A および B クロージャは 1 回割り当てられます。これらがスタックに割り当てられるかヒープに割り当てられるかはわかりませんが。ただし、一般に、これはリアルタイム システムで安全に使用できるようです。一方、B が何らかのラムダ関数 C を作成し、それを返す場合、C のメモリは割り当てと割り当て解除が繰り返され、リアルタイムでの使用には適していません。
疑似コードでは、DSP ループで、リアルタイムで安全になると思います。ブロック A を処理してから B を処理したいのですが、ここで A はその引数を呼び出します。これらの関数はどちらもstd::function
オブジェクトを返すため、環境がヒープに格納されるオブジェクトになりますf
。std::function
auto f = A(B); // A returns a function which calls B
// Memory for the function returned by A is on the heap?
// Note that A and B may maintain a state
// via mutable value-closure!
for (t=0; t<1000; t++) {
y = f(t)
}
そして、リアルタイムコードで使用するのは悪いかもしれないと私が思うもの:
for (t=0; t<1000; t++) {
y = A(B)(t);
}
そして、クロージャーにスタックメモリが使用される可能性が高いと思う場所:
freq = 220;
A = 2;
for (t=0; t<1000; t++) {
y = [=](int t){ return sin(t*freq)*A; }
}
後者の場合、ループの反復ごとにクロージャーが構築されますが、前の例とは異なり、関数呼び出しと同じようにヒープ割り当てが行われないため、安価です。さらに、コンパイラーがクロージャーを「持ち上げ」て、インライン化の最適化を行うことができるかどうか疑問に思います。
これは正しいです?ありがとうございました。