blogの更新がとんとご無沙汰してます。すんませんねー
なんかもー、本業でわたわたしてまして、おうち帰るとメシ食ってばたんきゅ、な日が続いてますのん。
わんくま東京勉強会も顔ださなくなっちゃいました。もーちょいで楽になるハズなんですけども。
先日MVP Open Dayにお邪魔しました。百名を超えるMVPのみなさんが顔を合わせ、新人MVPをいぢくり回す会ですわ(ホホホ
久しぶりにMVPのみなさんと顔をあわせ、ちょっとだけ元気をもらえたように思います。ありがとでした。
ちょっとだけ元気もらった勢いでVC++10のlambdaのカラクリを推測するココロミなど。
#include <iostream>
#include <typeinfo>
int main() {
int n;
auto lambda = [=](void* p) {
std::cout << p << '\t' << (void*)&n << std::endl;
};
int m;
lambda(&n);
lambda(&lambda);
lambda(&m);
std::cout << typeid(lambda).name() << std::endl;
}
こいつをコンパイル/実行すると
0028FDFC 0028FE00
0028FE00 0028FE00
0028FDF8 0028FE00
class `anonymous namespace'::<lambda0>
興味深い結果が得られました。どうやらメモリ上には:
0028FDF8: m
0028FDFC: n
0028FE00: lambda と lambda内のn
なんてなレイアウトでローカル変数が作られた様子。
n と lambda内のn とが異なる位置にあります。この二つは別物として扱われてるてことね。
値キャプチャされたnはlambda内で書き換えられないからくりがココにあるみたい。
また、lambdaとlambda内のnとが同じ位置にあること、lambdaの型がclassであることからしてlambda内のnはclassの最初のメンバとなってるポ。
してみるとコンパイラ君、おそらくはこんなコードを内部的に生成するのでしょう:
namespace {
class lambda0 {
int n_; // 値キャプチャしたn
public:
lambda0(int captured_var) : n_(captured_var) {}
void operator()(void* p) {
std::cout << p << '\t' << (void*)&n_ << std::endl;
}
}
}
int main() {
int m;
int n;
lambda0 lambda(n);
lambda(&n);
lambda(&lambda);
lambda(&m);
std::cout << typeid(lambda).name() << std::endl;
}
lambda式を定義するたんびにnanonymousな名前空間にコソーリclassを生成するのであれば、
C++/CLIでmanagedな変数をキャプチャできないことが説明つくです。class内にはmanagedは置けないもんね。