2012-02-02 28 views
5

Tôi đã làm việc trong một dự án một thời gian và tôi đã quyết định chuyển sang ARC. Tôi bắt gặp một số mã đã bị ném bom mỗi lần, và tôi muốn biết tại sao. Tôi đã cố gắng đơn giản hóa nó xuống đoạn mã này:ARC & Malloc: EXEC_BAD_ACCESS

typedef __strong id MYID; 

int main(int argc, char *argv[]) 
{ 
    MYID *arr = (MYID *) malloc(sizeof(MYID) * 4); 

    arr[0] = @"A";  // always get an EXEC_BAD ACCESS HERE 
    arr[1] = @"Test"; 
    arr[2] = @"Array"; 
    arr[3] = @"For"; 

    // uh oh, we need more memory 
    MYID *tmpArray = (MYID *) realloc(arr, sizeof(MYID) * 8); 
    assert(tmpArray != NULL); 

    arr = tmpArray; 

    arr[4] = @"StackOverflow"; // in my actual project, the EXEC_BAD_ACCESS occurs here 
    arr[5] = @"Is"; 
    arr[6] = @"This"; 
    arr[7] = @"Working?"; 

    for (int i = 0; i < 8; i++) { 
     NSLog(@"%@", arr[i]); 
    } 

    return 0; 
} 

Tôi không chắc điều gì đang xảy ra ở đây, mệt mỏi trong 4 dự án khác nhau và tất cả đều thất bại. Có điều gì sai với cuộc gọi malloc của tôi không? Đôi khi nó trả về null và các lần khác nó trả về một con trỏ mà tôi không thể truy cập.

+0

Tại sao typedef? Các con trỏ đối tượng không đủ điều kiện được giả định là '__strong'. –

+0

Bởi vì trong dự án thực tế, 'MYID' là một phần của cấu trúc (ccosrray của cocos2d). Ngoài ra, mã sẽ không biên dịch mà không có một vòng loại cho quyền sở hữu, bởi vì nó không phải là một phần của một bộ chọn mà chủ sở hữu có thể là 'tự'. –

+0

Tôi không chắc chắn những gì bạn có ý nghĩa bởi "bởi vì nó không phải là một phần của một bộ chọn mà chủ sở hữu có thể là" tự ". "Chủ sở hữu" của một đối tượng được phân bổ trong một phương thức là chính ngăn xếp, không phải là giá trị của 'tự'. Cũng lưu ý rằng bạn không thể đặt đối tượng '__strong' (hoặc' __weak') vào một cấu trúc C trong ARC, bạn phải sử dụng '__unsafe_unretained' và quản lý bộ nhớ một cách rõ ràng (ví dụ: với một số mã không phải ARC hoặc với' CFRetain() '/'CFRelease()'). –

Trả lời

13

Sự cố là vì bạn đang truyền bộ nhớ malloc'd vào một mảng đối tượng C. Thời điểm bạn cố gắng gán cho một trong các khe, ARC sẽ giải phóng giá trị trước đó, sẽ là bộ nhớ rác. Hãy thử sử dụng calloc() thay vì malloc() để nhận bộ nhớ zeroed và nó sẽ hoạt động.

Lưu ý rằng cuộc gọi realloc() của bạn cũng sẽ không điền bất kỳ bộ nhớ mới nào được phân bổ, vì vậy nếu bạn cần realloc() thì bạn có thể muốn sử dụng con trỏ tạm thời void* mà sau đó bạn điền bằng tay trước khi gán cho đối tượng của bạn mảng.

+3

dang. tế nhị. bạn thực sự phải biết rất nhiều về việc giữ lại/giải phóng/C để sử dụng ARC trong trường hợp này. – nielsbot

+0

Cảm ơn Kevin, đúng vậy. –

+0

@nielsbot: Chừng nào bạn còn dính vào Obj-C, bạn không nên có vấn đề gì. Loại điều này chỉ tăng lên khi cố gắng kết hợp các công cụ C cơ bản (như 'malloc()') với ARC. –

8

Chức năng malloc không phải là bộ nhớ mà nó phân bổ. Bộ nhớ có thể chứa rác ngẫu nhiên.

Từ hướng dẫn Clang Automatic Reference Counting, mục 4.2:

Đối __strong đối tượng, các pointee mới là lần đầu tiên giữ lại; thứ hai, các lvalue được nạp với ngữ nghĩa nguyên thủy; thứ ba, pointee mới được lưu vào lvalue với ngữ nghĩa nguyên thủy; và cuối cùng, điểm ảnh cũ được phát hành.

Vì vậy, những gì có thể xảy ra ở đây là malloc đang trả về bộ nhớ chứa các giá trị khác không phải ngẫu nhiên. ARC cố gắng sử dụng giá trị ngẫu nhiên đó làm con trỏ tới một đối tượng và giải phóng nó, nhưng nó không phải là một con trỏ đối tượng hợp lệ. Tai nạn.