9

__block変数にアクセスするブロックがコピーされた場合、変数がスタックからヒープに移動されることはわかっています。しかし、次のテスト コードは、変数がブロックのコピーの__blockにヒープに移動されることを示しています。

つまり、4 つの出力は次のとおりです: スタック => ヒープ => ヒープ => ヒープ、これは期待した結果ではありません: スタック => スタック => スタック => ヒープ。

誰かが私をまっすぐにすることができますか?

__block int x = 0;
int *pointerToX = &x;
//1. It's on the stack
NSLog(@"x's location is on the stack: %p", &x);
int (^block)() = ^{
    x += 1;
    return x;
};

//2. I think its stack, but it's heap
NSLog(@"x's location is on the %@: %p", (&x == pointerToX ? @"stack" : @"heap"), &x); //it's heap not stack

block();
//3. I think its stack, but it's heap
NSLog(@"x's location is on the %@: %p", (&x == pointerToX ? @"stack" : @"heap"), &x); //it's heap not stack

block = [block copy]; // The variable x will be moved to the heap
//4. I think its stack, but it's heap
NSLog(@"x's location is on the %@: %p", (&x == pointerToX ? @"stack" : @"heap"), &x); //heap
4

3 に答える 3

3

はじめに、ブロックは奇妙です。

さて、最初に、変数 x を宣言し、接頭辞を付けました__block。いったい何なの__block?ブロックのレキシカルスコープでキャプチャされたオブジェクトの-retain場合、ブロックが実行されたときにそれらが存在することを保証するために変数が編集されます。constただし、プリミティブ変数の場合、ブロックは、参照ではなく値によって渡されるように強制することにより、値を保護します。を先頭__blockに追加することで、ブロックがコピーされるときに変数を「魔法のように」スタックからヒープに移動する自由をコンパイラに与えます。明確にするために、__block変数は実際にはスタックに割り当てられますがmalloc()、ブロックがコピーされるとヒープ ( 'd) に移動されます。

しかし、x の位置の奇妙な変化はどうでしょうか? さて、また話を戻し__blockます。通常の変数のように x への参照を使用していないためconst、ブロックは (少し厄介な) トリックを使用します__block。タダ!変数はスタックからヒープに移動しませんでした。ブロックは変数へのポインタを逆参照してメモリに移動しただけです。

したがって、変数がいつどこに移動するかについて、本当に混乱しています。あなたの例は正しい値を記録しています。

于 2013-02-26T07:06:02.550 に答える
2

予想される出力は、ブロックがステップ 3-4 までコピーされないという仮定に基づいています。ただし、Blocks の仕様には、それが当てはまることを保証するものは何もありません。

はい、明示的に呼び出すと、ブロックは遅くともコピーされます-copy。しかし、なぜそれを早くコピーできないのでしょうか? ブロックを先にコピーすることは決して間違ったことではありません。したがって、ブロックが正確にいつコピーされるかは未定義であり、それに依存するべきではありません。

ARC の下にあるコンパイラの最近のバージョンの中には、保守的で、ブロックが作成された直後にコピーするものがあります。それは何も悪いことではありません。繰り返しますが、それを行う場合、それは実装の詳細であり、他のコンパイラまたは将来のバージョンは何か異なることを行う可能性があります.

于 2013-02-26T08:49:21.640 に答える
0

In Objective-C with ARC, what does compiler do when I define a block?で同じ質問をしました。

ARC でコードを実行する場合

アークでは、

保持可能なオブジェクト所有者型のブロック変数は、スタック コピーからの移動の結果でヒープ コピーを初期化することにより、スタックから移動されます。

http://clang.llvm.org/docs/AutomaticReferenceCounting.html#blocks

于 2013-02-26T14:04:58.550 に答える