2009-06-10 36 views
8

Bản sao có thể xảy ra:
How does the standard new operator work in c++?
How does delete[] “know” the size of the operand array?Làm thế nào để xóa [] biết kích thước của một mảng?

Dupe của How does delete[] "know" the size of the operand array?

Tôi tò mò như thế nào delete [] con số ra kích thước của bộ nhớ được phân bổ. Khi tôi làm điều gì đó như:

int* table = new int[5]; 
delete[] table; 

Tôi hiểu rằng bộ nhớ của bảng được giải phóng. Nhưng điều gì sẽ xảy ra nếu tôi gán lại con trỏ cho một số bảng khác.

int* table = new [5]; 
int* table2 = new [9]; 
table = table2; 
delete[] table; 

Tôi có thể miễn phí một bảng có kích thước 5 hoặc 9 không? Tôi quan tâm đến cách [] và xóa [] chia sẻ thông tin về kích thước của chúng. Hoặc có lẽ tôi đang thiếu một cái gì đó thiết yếu ở đây.

+0

Bản sao (nhiều hơn hoặc ít hơn) của http://stackoverflow.com/questions/377178/how-does-the-standard-new-operator-work-in-c/377208 –

+3

Tôi không đồng ý, điều này cụ thể hơn. –

+0

Như một lưu ý phụ, và như đã đề cập trong các câu trả lời, đây là công cụ cụ thể. Điều đó có nghĩa rằng bạn không nên dựa vào cách nó được thực hiện để trích xuất kích thước của mảng, vì nó có thể thay đổi từ trình biên dịch sang trình biên dịch, và từ phiên bản trình biên dịch sang phiên bản trình biên dịch. –

Trả lời

10

Nó sẽ xóa một mảng có kích thước 9. Nó xóa mảng được trỏ tới bởi con trỏ.

Không xác định cách thông tin kích thước được lưu trữ, do đó, mỗi trình biên dịch có thể thực hiện theo cách khác, nhưng cách phổ biến để làm là phân bổ khối bổ sung trước mảng. Tức là, khi bạn thực hiện việc này:

int* table = new int[5]; 

nó thực sự phân bổ một mảng gồm 6 số nguyên và lưu trữ kích thước mảng trong phần tử đầu tiên. Sau đó, nó trả về một con trỏ đến phần tử thứ hai. Vì vậy, để tìm kích thước, xóa [] chỉ cần đọc bảng [-1], về cơ bản.

Đó là một cách phổ biến để làm điều đó, nhưng tiêu chuẩn ngôn ngữ không chỉ định rằng nó phải được thực hiện theo cách này. Chỉ cần có hoạt động.

Cách tiếp cận khác có thể là sử dụng địa chỉ của mảng làm khóa vào một số bảng băm chung. Bất kỳ phương pháp nào đều hợp lệ, miễn là nó tạo ra kết quả chính xác.

+0

Cảm ơn bạn, lời giải thích này rất có ý nghĩa đối với tôi.Mặc dù tôi rất muốn chọn nhiều câu trả lời làm câu trả lời được chấp nhận. – Lucas

16

Section 16.14 của C++ Hỏi đáp câu trả lời Lite này:

Có hai kỹ thuật phổ biến mà làm điều này. Cả hai kỹ thuật này đều sử dụng bởi các trình biên dịch cấp thương mại, cả hai đều có sự cân bằng, và cả hai đều không phải là hoàn hảo. Những kỹ thuật này là:

* Over-allocate the array and put n just to the left 
    of the first Fred object. 
* Use an associative array with p as the key and n as the value. 
+1

Bạn có thể trích dẫn một trình biên dịch với mảng kết hợp không? – curiousguy

+0

@curiousguy Theo liên kết trong Câu hỏi thường gặp CFront, hãy sử dụng: http://www.parashift.com/c%2B%2B-faq-lite/compiler-dependencies.html#faq-38.8 –

+0

Ý bạn là trình biên dịch không bao giờ có các mẫu hiện đại, mà đã không liên quan cách đây 15 năm, với [bản phát hành cuối cùng vào năm 1991] (http://www.softwarepreservation.org/projects/c_plus_plus/index.html#cfront): "_Bjarne Stroustrup notes", Một cảnh báo Cfront 3 là chuẩn trước và dứt khoát không được khuyến khích sử dụng hoặc phát triển hơn nữa có thể được đưa ra. "_" – curiousguy

0

tôi đoán là mới [] thực sự phân bổ nhiều dữ liệu hơn vẻ bề ngoài. Nó có thể có một vài byte trước khi con trỏ được trả về cho biết có bao nhiêu mục trong mảng.

4

Cách thực hiện này là chi tiết trình biên dịch cụ thể. Nhưng cuộc gọi để xóa [], giả sử không có tham nhũng bộ nhớ, sẽ luôn xóa đúng số phần tử. Có một số cách để đạt được điều này nhưng một cách đơn giản là ẩn chiều dài trong bộ nhớ.

Đây là cách tốt nhất và đơn giản để thực hiện điều này cho mục đích trình diễn. Giả sử mã của bạn gọi int mới [10].Thay vì phân bổ 10 * sizeof (int), trình biên dịch phân bổ (10 * sizefo (int)) + sizeof (size_t). Sau đó nó trả về một con trỏ cho bạn mà được bù đắp size_t từ đầu. Bên trong không gian size_t ban đầu nó viết số 10. Bây giờ khi bạn gọi delete [] và truyền vào một con trỏ, trình biên dịch chỉ cần đi ngược lại size_t bytes và tìm số lượng các phần tử cần xóa.

+0

Argh bạn đánh tôi với nó - sẽ đăng một ví dụ tương tự. – gnud

+0

Đó là một ví dụ về ẩn nó trong bộ nhớ được cấp phát, không phải "ẩn nó trong con trỏ". –

+0

@Dan, yep đã sửa lỗi đánh máy – JaredPar

1

Cơ chế này phụ thuộc vào việc triển khai thực hiện, nhưng nó sẽ không bị "lừa", bởi bạn gán lại con trỏ trong ví dụ của bạn. Nó sẽ deallocate mảng kích thước 9, giống như bạn đã nói với nó (và trong trường hợp này sẽ có một rò rỉ bộ nhớ vì mảng kích thước 5 bây giờ không có gì trỏ đến nó).

2

Cách xóa [] hoạt động phụ thuộc vào triển khai thực hiện, nhưng toán tử mới kết hợp bộ mô tả với bộ nhớ được phân bổ theo cách nào đó (trong hầu hết các trường hợp, nó được thêm vào bộ nhớ được cấp phát hoặc được lưu trữ trong bảng tra cứu). Bộ mô tả chứa kích thước thực của bộ nhớ được cấp phát.

Trong ví dụ mã thứ hai của bạn, xóa [] sẽ xóa chính xác mảng chín phần tử của int và mảng năm phần tử gốc sẽ bị rò rỉ.

0

Bạn có thể tưởng tượng rằng các cửa hàng hệ thống kích thước của bảng trong một cấu trúc như thế này:

struct MemoryAllocated 
    { 
    size_t sizeOfMemory; 
    char* yourData; 
    } 

mỗi loại phân bổ của một số bộ nhớ, hệ thống trả về một con trỏ đến 'yourData'. Và mỗi loại bộ nhớ của bạn là 'miễn phí', hệ thống sẽ chuyển con trỏ để có được 'sizeOfMemory'. Xem thêm std :: allocator

0

trong trường hợp []/delete [] mới, điều xảy ra trí nhớ giống như/tương tự với những gì xảy ra trong trường hợp mới/xóa ... thông tin kích thước được lưu trữ bên trong (lớn hơn) phân bổ chính khối. điều thú vị đối với mảng là nó cũng sử dụng thông tin kích thước để biết có bao nhiêu đối tượng gọi destructors trên đó.

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