2010-03-09 31 views
18

Khi bạn phân bổ một mảng bằng cách sử dụng new [], tại sao bạn không thể tìm ra kích thước của mảng đó từ con trỏ? Nó phải được biết trong thời gian chạy, nếu không delete [] sẽ không biết có bao nhiêu bộ nhớ để giải phóng.Tại sao không thể truy cập kích thước của mảng [] 'd mới?

Trừ khi tôi bỏ lỡ điều gì đó?

+0

Một thiết kế đơn giản không cần phải biết - trong một trường hợp phức tạp, bạn phải tự mình quản lý rất nhiều. Có chức năng gỡ lỗi chung cho trình biên dịch của bạn sẽ cho bạn biết - nhưng nếu bạn cần thiết kế của bạn có lẽ là sai. –

+0

Tôi thường tự hỏi tại sao bạn không bao giờ thấy một người cấp phát không biết kích thước, và yêu cầu nó phải được thông qua khi xóa. bởi vì bao lâu bạn đã từng xóa một khối bộ nhớ và không thể dễ dàng tính toán kích thước của nó? Tôi đoán không bao giờ có thực sự là một lợi ích để thực hiện một hệ thống với giới hạn này ... – matt

+0

Nó có lẽ sẽ đặt những hạn chế không cần thiết về việc thực hiện một hoạt động cấp thấp như vậy. Sau khi tất cả các bạn đã biết bao nhiêu bạn yêu cầu khi bạn phân bổ mảng, do đó, không có nhu cầu bức xúc của thời gian chạy để có thể cho bạn biết rằng. – UncleBens

Trả lời

14

Trong triển khai điển hình, kích thước của khối bộ nhớ động bằng cách nào đó được lưu trữ trong chính khối - điều này đúng. Nhưng không có cách nào tiêu chuẩn để truy cập thông tin này. (Việc triển khai có thể cung cấp các cách triển khai cụ thể để truy cập nó). Đây là cách thực hiện với malloc/free, đây là cách thực hiện với new[]/delete[]. Trong thực tế, trong một phân bổ bộ nhớ thực hiện điển hình cho các cuộc gọi new[]/delete[] cuối cùng được xử lý bởi một số cặp malloc/free thực hiện cụ thể, có nghĩa là delete[] không thực sự quan tâm đến bao nhiêu bộ nhớ để deallocate: nó đơn giản các cuộc gọi nội bộ free (hoặc bất kỳ tên nào được đặt tên), sẽ đảm nhiệm điều đó.

Điều gì delete[] cần biết mặc dù có bao nhiêu phần tử để hủy trong các trường hợp khi loại phần tử mảng có destructor không tầm thường. Và đây là câu hỏi của bạn - số phần tử mảng, không phải kích thước của khối (hai số này không giống nhau, khối có thể lớn hơn mức thực sự cần thiết cho mảng đó). Vì lý do này, số lượng phần tử trong mảng thường được lưu trữ bên trong khối bởi new[] và sau đó được truy xuất bởi delete[] để thực hiện hủy phần tử mảng phù hợp. Không có cách nào tiêu chuẩn để truy cập vào số này.

(Điều này có nghĩa rằng trong trường hợp tổng quát, một khối bộ nhớ điển hình được phân bổ bởi new[] sẽ độc lập, đồng thời lưu trữ cả kích thước khối bằng byte số lượng phần tử mảng. Những giá trị được lưu trữ bởi mức độ khác nhau của C++ cơ chế cấp phát bộ nhớ - cấp phát bộ nhớ thô và new[] tương ứng - và không tương tác với nhau theo bất kỳ cách nào).

Tuy nhiên, lưu ý rằng vì những lý do trên, số phần tử mảng thường chỉ được lưu trữ khi loại phần tử mảng có destructor không tầm thường. I E. số này không phải lúc nào cũng có mặt. Đây là một trong những lý do tại sao cung cấp một cách tiêu chuẩn để truy cập vào dữ liệu đó là không khả thi: bạn phải lưu trữ nó luôn (làm lãng phí bộ nhớ) hoặc hạn chế tính khả dụng của nó bằng loại hủy (gây nhầm lẫn).

Để minh họa ở trên, khi bạn tạo một mảng của int s

int *array = new int[100]; 

kích thước của mảng (tức là 100) là không thường được lưu trữ bởi new[] từ delete[] không quan tâm đến nó (int không có destructor). Kích thước vật lý của khối theo byte (như, 400 byte hoặc hơn) thường được lưu trữ trong khối bởi bộ cấp phát bộ nhớ thô (và được sử dụng bởi bộ giải mã bộ nhớ thô được gọi bởi delete[]), nhưng nó có thể dễ dàng hóa ra là 420 đối với một số lý do thực hiện cụ thể. Vì vậy, kích thước này về cơ bản là vô dụng đối với bạn, vì bạn sẽ không thể lấy được kích thước mảng gốc chính xác từ nó.

+1

Có, bộ cấp phát bộ nhớ có thể không biết kích thước của mảng, có thể đã trả lại một khối có kích thước lớn nhất tiếp theo và thậm chí không quan tâm bạn chỉ sử dụng 75% nó. –

7

Bạn có nhiều khả năng truy cập vào nó, nhưng nó sẽ yêu cầu kiến ​​thức thân mật về người cấp phát của bạn và sẽ không thể di chuyển được. Tiêu chuẩn C++ không chỉ định cách triển khai lưu trữ dữ liệu này, vì vậy không có phương pháp nhất quán để có được nó. Tôi tin rằng nó không được chỉ định bởi vì các nhà phân bổ khác nhau có thể muốn lưu trữ nó theo những cách khác nhau cho mục đích hiệu quả.

+0

Tuy nhiên, sẽ rất tuyệt nếu như Standard đã chỉ định toán tử 'len (...)' để có thể nhận được kích thước của mảng bằng toán tử đó (và các tác giả có thể triển khai toán tử len như họ muốn). .. :( – smerlin

+4

@smelin Không phải là những gì 'std :: vector <>' là dành cho? – KitsuneYMG

5

Có ý nghĩa, ví dụ như kích thước của khối được phân bổ có thể không nhất thiết phải có cùng kích thước với mảng. Trong khi it is true rằng new[] có thể lưu trữ số lượng các phần tử (gọi từng phần tử huỷ), nó không phải vì nó sẽ không được yêu cầu cho một destructor rỗng. Cũng không có cách tiêu chuẩn (C++ FAQ Lite 1, C++ FAQ Lite 2) của việc triển khai nơi new[] lưu trữ độ dài mảng theo từng phương pháp có ưu và nhược điểm của nó.

Nói cách khác, nó cho phép phân bổ nhanh nhất có thể bằng cách không chỉ định bất kỳ điều gì về việc triển khai. (Nếu việc thực hiện phải lưu trữ kích thước của mảng cũng như kích thước của khối được phân bổ mỗi lần, nó sẽ lãng phí bộ nhớ mà bạn có thể không cần).

3

Nói một cách đơn giản, tiêu chuẩn C++ không yêu cầu hỗ trợ cho điều này. Có thể là nếu bạn biết đủ về nội bộ của trình biên dịch, bạn có thể tìm ra cách truy cập thông tin này, nhưng điều đó sẽ nói chung là được coi là thực hành không tốt. Lưu ý rằng có thể có một sự khác biệt trong bố trí bộ nhớ cho mảng phân bổ heap và mảng phân bổ stack. Hãy nhớ rằng về cơ bản những gì bạn đang nói đến ở đây là các mảng kiểu C, quá - mặc dù newdelete là các toán tử C++ - và hành vi được kế thừa từ C. Nếu bạn muốn một mảng C++ "đó là có kích thước, bạn nên sử dụng STL (ví dụ: std :: vector, std :: deque).

+0

Vâng, tôi thường không sử dụng mảng kiểu C - nó chỉ là một câu hỏi chung vì nó (nếu nó là Có thể) tiết kiệm một số bộ nhớ trong nhiều trường hợp –

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