2013-02-26 37 views
8

Tôi biết rằng biến số __block sẽ được chuyển sang vùng heap từ ngăn xếp nếu truy cập Chặn được sao chép. Nhưng mã thử nghiệm sau đây cho tôi thấy biến số __block được di chuyển đến vùng heap trước khi sao chép một khối của.Tại sao biến __block được di chuyển đến heap TRƯỚC KHI khối được sao chép?

Tức là, bốn đầu ra là: stack => heap => heap => heap, không phải là kết quả mong đợi của tôi: stack => stack => stack => heap.

Ai đó có thể làm thẳng tôi không?

__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 
+0

lý do tại sao bạn quan tâm về vấn đề này không? và điều gì xảy ra với '__block int x; int * ptr = & x; 'nếu biến được chuyển từ stack sang heap? –

+2

Đó là chi tiết triển khai. Bạn nên cố gắng không suy nghĩ quá nhiều về chúng. –

+2

Ghi lại lớp của khối (có, khối là đối tượng) cũng hữu ích trong việc xác định nơi nó được sao chép vào ('__NSStackBlock__',' __NSMallocBlock__'). – CodaFi

Trả lời

3

Hãy để tôi nói trước điều này bằng cách nói: Các khối lạ.

Bây giờ, khi bạn bắt đầu, bạn đã khai báo biến x và cũng có tiền tố là __block. Cái quái gì là __block dù sao đi nữa? Vâng, đối với các đối tượng được chụp trong phạm vi từ vựng của khối, các biến là -retain 'ed để đảm bảo chúng xung quanh khi khối được thực hiện. Nhưng đối với các biến nguyên thủy, các khối bảo đảm giá trị của chúng bằng cách buộc chúng được chuyển qua giá trị const thay vì tham chiếu. Bằng cách thêm trước __block, bạn đã cho trình biên dịch miễn phí trị vì di chuyển biến của bạn "kỳ diệu" từ ngăn xếp đến đống khi khối được sao chép. Để rõ ràng, trên thực tế, các biến số __block được phân bổ, nhưng chúng được chuyển sang vùng heap (malloc() 'd) khi khối được sao chép.

Nhưng những thay đổi kỳ lạ ở vị trí của x thì sao? Vâng, quay lại __block một lần nữa. Bởi vì bạn không sử dụng tham chiếu const cho x như biến thông thường, các khối sử dụng mẹo (hơi khó chịu): Một khối tạo ra một con trỏ tới bất kỳ biến số __block nào và nếu biến đó bị biến đổi, nó sẽ bị bỏ qua. Ta da! Biến của bạn không di chuyển từ ngăn xếp đến heap, khối chỉ đơn thuần là dereferenced con trỏ vào nó và di chuyển nó trong bộ nhớ!

Vì vậy, thực sự, bạn đang bối rối về vị trí và thời điểm các biến của bạn được di chuyển xung quanh. Ví dụ của bạn đang ghi lại các giá trị chính xác.

+0

"Nhưng đối với các biến nguyên thủy, các khối an toàn các giá trị của chúng bằng cách buộc chúng được chuyển qua giá trị const thay vì tham chiếu." Điều đó đúng cho tất cả các loại. Các biến không '' chặn', bất kể loại nào, được ghi lại theo giá trị khi khối được tạo. – newacct

2

Sản lượng dự kiến ​​của bạn dựa trên giả thiết rằng khối không được sao chép cho đến bước 3-4. Tuy nhiên, không có gì trong các đặc tả Blocks đảm bảo rằng đó là trường hợp.

Có, khối sẽ được sao chép muộn nhất khi bạn gọi rõ ràng -copy trên đó. Nhưng tại sao nó không thể được sao chép trước đó? Nó không bao giờ là sai để sao chép một khối trước đó. Vì vậy, khi chính xác một khối được sao chép là không xác định, và bạn không nên phụ thuộc vào nó.

Một số phiên bản gần đây của trình biên dịch trong ARC có thể bảo thủ và sao chép một khối ngay sau khi được tạo. Chẳng có vấn đề gì với việc đấy cả. Một lần nữa, nếu nó làm điều đó, nó sẽ là một chi tiết thực hiện, và trình biên dịch khác hoặc các phiên bản trong tương lai có thể làm một cái gì đó khác nhau.

0

Tôi hỏi một câu hỏi tương tự tại In Objective-C with ARC, what does compiler do when I define a block?

Trường hợp bạn chạy mã trong ARC

Trong ARC,

khối biến của retainable loại chủ sở hữu đối tượng được di chuyển ra khỏi ngăn xếp bằng cách khởi tạo bản sao đống với kết quả di chuyển từ bản sao ngăn xếp .

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

+0

Khi trích dẫn các bài đăng khác, hãy đảm bảo đưa vào trích dẫn chính xác. –

+0

CÓ, nó do ARC gây ra. – jcccn

Các vấn đề liên quan