[解決済み] C++11のラムダ実装とメモリモデル
質問
C++11 のクロージャについて正しく考えるための情報が欲しいのですが、クロージャと
std::function
について、どのように実装され、どのようにメモリが処理されるかという観点から、正しく考える方法についての情報が欲しいです。
私は時期尚早な最適化は信じていませんが、新しいコードを書くときに、自分の選択がパフォーマンスに与える影響を注意深く考慮する習慣はあります。 また、マイクロコントローラーやオーディオシステムなど、非決定的なメモリの割り当て/解放の一時停止を回避するようなリアルタイムプログラミングをかなり行っています。
したがって、私は、C++ラムダをいつ使用するか、または使用しないかについて、より良い理解を深めたいと思います。
私の現在の理解は、キャプチャされたクロージャを持たないラムダは、まさにCのコールバックのようなものだということです。 しかし、環境が値または参照によってキャプチャされるとき、匿名オブジェクトがスタック上に作成されます。 値によるクロージャを関数から返さなければならない場合、それを
std::function
. この場合、クロージャのメモリはどうなるのでしょうか? スタックからヒープにコピーされるのでしょうか? クロージャメモリが解放されるのは
std::function
が解放されるたびに解放されるのでしょうか?
std::shared_ptr
?
リアルタイムシステムにおいて、ラムダ関数のチェーンを設定し、Aへの継続引数としてBを渡すことで、処理パイプラインが
A->B
が作られる。 この場合、AとBのクロージャは一度確保されることになる。 これがスタックに確保されるのかヒープに確保されるのかはわからないが。 しかし、一般に、これはリアルタイム・システムで使用しても安全だと思われる。 一方、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; }
}
後者の場合、クロージャはループの各反復で構築されますが、前の例とは異なり、関数呼び出しのようにヒープ割り当てが行われないため、安価になります。 さらに、コンパイラはクロージャを持ち上げ、インライン最適化を行うことができるのでしょうか。
これは正しいのでしょうか? ありがとうございます。
どのように解決するのですか?
<ブロッククオート私の現在の理解では、キャプチャされたクロージャのないラムダは、C のコールバックとまったく同じです。しかし、環境が値または参照によってキャプチャされると、スタック上に匿名オブジェクトが作成されます。
いいえ、それは 常に であり、スタック上に生成された未知の型のC++オブジェクトです。キャプチャのないラムダは 変換される を関数ポインタに変換することができますが(ただし、C の呼び出し規約に適しているかどうかは実装に依存します)、だからといって は 関数ポインタであることを意味するものではありません。
関数から値クロージャを返さなければならないとき、それをstd::functionでラップすることがあります。この場合、クロージャのメモリはどうなるのでしょうか?
C++11ではラムダは特別なものではなく、他のオブジェクトと同じようにオブジェクトです。ラムダ式の結果は一時的なもので、スタック上の変数を初期化するために使用することができます。
auto lamb = []() {return 5;};
lamb
はスタックオブジェクトです。これはコンストラクタとデストラクタを持っています。そして、それに関するすべての C++ の規則に従います。の型は
lamb
の型には、取り込まれた値や参照が含まれます。それらは、他の型のオブジェクトのメンバと同じように、そのオブジェクトのメンバとなります。
に与えることができます。
std::function
:
auto func_lamb = std::function<int()>(lamb);
この場合
コピー
の値の
lamb
. もし
lamb
が何かを値で捕捉していた場合、それらの値のコピーが2つ存在することになります;1つは
lamb
に、もうひとつは
func_lamb
.
現在のスコープが終了したとき。
func_lamb
は破棄され、その後に
lamb
が破壊され、スタック変数のクリーンアップのルールに従います。
ヒープ上のものを割り当てることも同様に簡単にできます。
auto func_lamb_ptr = new std::function<int()>(lamb);
の内容のメモリは、まさに
std::function
のメモリがどこにあるかは実装に依存します。
std::function
が採用する型消去は一般に少なくとも1回のメモリ割り当てを必要とします。このため
std::function
のコンストラクタがアロケータを取ることができるのはこのためです。
std::function が解放されるたびに解放されるのか、つまり std::shared_ptr のように参照カウントされるのか?
std::function
には
コピー
を格納します。事実上すべての標準ライブラリC++型と同様に
function
は
値セマンティクス
. したがって,コピー可能であり,コピーされた場合,新しい
function
オブジェクトは完全に分離されます。また、移動可能であるため、内部での割り当ては、さらに割り当てもコピーも必要なく、適切に転送することができます。
したがって、参照カウントは必要ありません。
あなたが述べる他のすべては、"メモリ割り当て"が"リアルタイムコードで使用するのが悪い"に等しいと仮定すると、正しいです。
関連
-
[解決済み】CMakeエラー at CMakeLists.txt:30 (project)。CMAKE_C_COMPILER が見つかりませんでした。
-
[解決済み】エラー。引数リストに一致するコンストラクタのインスタンスがない
-
[解決済み] Javaでメモリーリークを発生させるにはどうしたらいいですか?
-
[解決済み] C++11では、標準化されたメモリモデルが導入されました。その意味するところは?そして、C++プログラミングにどのような影響を与えるのでしょうか?
-
[解決済み] なぜ、オブジェクトそのものではなく、ポインタを使用しなければならないのですか?
-
[解決済み] C#がforeachで変数を再利用するのは理由があるのか?
-
[解決済み] アプリケーションやプロセスの実際のメモリ使用量を測定するにはどうすればよいですか?
-
[解決済み] Distinct() with lambda?
-
[解決済み】C++11のラムダ式って何?
-
[解決済み】なぜC++プログラマは'new'の使用を最小限に抑えなければならないのでしょうか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] テスト
-
[解決済み】Visual Studio 2015で「非標準の構文。'&'を使用してメンバーへのポインターを作成します」エラー
-
[解決済み】変数 '' を抽象型 '' と宣言できない。
-
[解決済み] クラスにデフォルトコンストラクタが存在しない。
-
[解決済み】エラー:strcpyがこのスコープで宣言されていない
-
[解決済み】「Expected '(' for function-style cast or type construction」エラーの意味とは?
-
[解決済み】リンカーエラーです。"リンカ入力ファイルはリンクが行われていないため未使用"、そのファイル内の関数への未定義参照
-
[解決済み】エラー:不完全な型へのメンバーアクセス:前方宣言の
-
[解決済み] [Solved] インクルードファイルが開けません。'stdio.h' - Visual Studio Community 2017 - C++ Error
-
[解決済み】std::cin.getline( ) vs. std::cin