2011-12-06 19 views
18

Tôi đã đọc rằng toán tử delete[] là cần thiết vì môi trường thời gian chạy không giữ thông tin về nếu khối được phân bổ là một mảng đối tượng yêu cầu hủy cuộc gọi hay không, nhưng nó thực sự giữ thông tin về vị trí trong bộ nhớ được cấp phát khối được lưu trữ, và cũng, tất nhiên, kích thước của khối.
Nó sẽ chỉ mất thêm một chút dữ liệu meta để nhớ xem các trình phá hủy có cần phải được gọi khi xóa hay không, vậy tại sao không chỉ thực hiện điều đó?Tại sao môi trường thời gian chạy không thể quyết định áp dụng xóa hoặc xóa [] thay vì lập trình viên?

Tôi chắc chắn có một lời giải thích tốt, tôi không đặt câu hỏi, tôi chỉ muốn biết điều đó.

+0

Bạn có hỏi tại sao có 'xóa []' thay vì 'xóa' xử lý thỏa thuận và hủy bỏ mảng không? –

+0

Nó là một chi phí nhỏ, nhưng sau đó, thu được để trả nó cũng rất nhỏ. –

+2

Trừ khi tiêu chuẩn nói rõ ràng rằng kích thước của phân bổ được lưu trữ ở đâu đó (tôi nghi ngờ nó), nó không phải là luôn luôn cần thiết để lưu trữ kích thước được phân bổ. Lấy ví dụ sau: 'int * p = new int;' Cách duy nhất để xóa nó theo một cách xác định là gọi delete trên 'int *'. Vì vậy, kích thước được ngầm biết từ thực tế bạn biết nó là một 'int'. (Lưu ý, gọi xóa trên một 'void *' là UB: http://stackoverflow.com/a/941959/239916). –

Trả lời

3

Có hai điều cần được xóa tại đây.

Đầu tiên: giả định rằng malloc giữ kích thước chính xác mà bạn đã hỏi.

Không thực sự. malloc chỉ quan tâm đến việc cung cấp một khối đủ lớn. Mặc dù vì lý do hiệu quả, nó sẽ không thể phân bổ nhiều, nó vẫn có thể cung cấp cho bạn một khối có kích thước "chuẩn", ví dụ: khối 2^n byte. Do đó kích thước thực (như trong, số lượng các đối tượng thực sự được phân bổ) là không rõ.

Thứ hai: "thêm chút" cần

Trên thực tế, các thông tin cần thiết cho một đối tượng nhất định phải biết cho dù đó là một phần của một mảng hay không chỉ đơn giản là sẽ là một chút thêm. Hợp lý.

Theo như thực hiện được quan tâm mặc dù: nơi bạn thực sự sẽ đặt bit đó?

Bộ nhớ được cấp phát cho chính đối tượng có thể không được chạm vào, đối tượng sẽ sử dụng nó sau khi tất cả. Vì thế ?

  • trên một số nền tảng, điều này có thể được lưu giữ trong con trỏ bản thân (một số nền tảng lờ đi một phần của bit), nhưng điều này không phải là di
  • nên nó sẽ đòi hỏi thêm dung lượng, ít nhất là một byte, trừ rằng với các vấn đề liên kết nó cũng có thể lên đến 8 byte.

diễn: (không có sức thuyết phục như ghi nhận của sth, xem dưới đây)

// A plain array of doubles: 
+-------+-------+------- 
| 0 | 1 | 2 
+-------+-------+------- 

// A tentative to stash our extra bit 
+-------++-------++-------++ 
| 0 || 1 || 2 || 
+-------++-------++-------++ 

// A correction since we introduced alignment issues 
// Note: double's aligment is most probably its own size 
+-------+-------+-------+-------+-------+------- 
| 0 | bit | 1 | bit | 2 | bit 
+-------+-------+-------+-------+-------+------- 

Humpf!

EDIT

Do đó, trên hầu hết các nền tảng (nơi địa chỉ làm vấn đề), bạn sẽ cần phải "mở rộng" mỗi con trỏ, và thực sự tăng gấp đôi kích thước của chúng (các vấn đề liên kết).

Có thể chấp nhận cho tất cả các con trỏ chỉ lớn gấp hai lần để bạn có thể thêm một chút không? Đối với hầu hết mọi người tôi đoán nó sẽ được. Nhưng C++ không được thiết kế cho hầu hết mọi người, nó được thiết kế chủ yếu cho những người quan tâm đến hiệu suất, cho dù tốc độ hay bộ nhớ, và như vậy điều này là không thể chấp nhận được.

END OF EDIT

Vì vậy, câu trả lời đúng là gì? Câu trả lời đúng là khôi phục thông tin mà hệ thống kiểu bị mất là tốn kém. Không may.

+1

Bạn sẽ không thực sự cần lưu trữ một chút cho mỗi phần tử mảng vì nó không hợp lệ để 'xóa' một con trỏ tới một phần tử" bên trong "mảng đó. Chỉ cho phần tử đầu tiên bạn cần có khả năng xác định xem toàn bộ mảng có tuân theo nó hay không. – sth

+0

@sth: đúng, bản trình diễn là thiếu sót ... và tôi đã dành rất nhiều tình yêu cho bản vẽ ASCII của mình: (Tôi đã sửa chữa, cảm ơn thông báo. –

+0

Một lần nữa, bạn đã kiểm tra chi phí của các bộ phân bổ heapal mục đích gneral? –

10

Tôi nghĩ lý do là C++ không ép bạn vào bất kỳ thứ gì bạn không muốn. Nó sẽ bổ sung thêm siêu dữ liệu và nếu ai đó không sử dụng nó, thì chi phí thừa sẽ bị ép buộc đối với chúng, trái ngược với mục tiêu thiết kế của ngôn ngữ C++.

Khi bạn muốn khả năng bạn mô tả, C++ không cung cấp cách. Nó được gọi là std::vector và bạn hầu như luôn luôn thích nó, một loại container khác, hoặc một con trỏ thông minh trên raw newdelete.

+0

Có lẽ ... mặc dù người ta có thể tranh luận rằng ngữ nghĩa mảng trong C đã bị hỏng nên nó chỉ đang diễn ra từ đó. Tôi sợ rằng để lại kích thước ra là một vi-tối ưu hóa sớm. –

+0

Tôi không nghĩ đây là câu hỏi. –

+0

Về 'std :: vector' ... không hoàn toàn vì nó có thể phát triển động. Một thùng chứa đơn giản hơn sẽ hoạt động. Tuy nhiên, đủ gần. –

4

C++ cho phép bạn hiệu quả nhất có thể, vì vậy nếu họ phải theo dõi số phần tử trong một khối sẽ chỉ là 4 byte phụ được sử dụng cho mỗi khối.

Điều này có thể hữu ích cho nhiều người, nhưng nó cũng ngăn chặn hiệu quả tổng thể cho những người không ngại đặt [].

Điều này tương tự như sự khác biệt giữa C++ và Java. Java có thể nhanh hơn nhiều vì bạn không bao giờ phải lo lắng về việc thu gom rác, nhưng C++, nếu được lập trình đúng, có thể hiệu quả hơn và sử dụng ít bộ nhớ hơn vì nó không phải lưu trữ bất kỳ biến nào và bạn có thể quyết định khi nào xóa khối bộ nhớ.

+2

Bây giờ đi và kiểm tra bất kỳ phân bổ heap mục đích chung, và xem có bao nhiêu chi phí cho mỗi phân bổ. Tôi sẽ không ngạc nhiên bởi những con số như 16-64 byte cho mỗi phân bổ, do đó, 4-8 byte cho kích thước sẽ không ai nhận thấy. Và một lần nữa, có lẽ hầu hết các nhà phân bổ đều theo dõi phân bổ. –

4

Về cơ bản, thiết kế ngôn ngữ không muốn đặt quá nhiều hạn chế đối với người triển khai. Nhiều thời gian chạy C++ sử dụng malloc() cho ::operator new()free() (nhiều hơn hoặc ít hơn) cho ::operator delete(). Tiêu chuẩn malloc/free không cung cấp sổ sách kế toán cần thiết để ghi lại một số yếu tố và không cung cấp cách xác định kích thước của kích thước malloc 'tại thời gian free. Thêm một mức độ thao tác bộ nhớ khác giữa new Foomalloc cho mỗi đối tượng đơn lẻ, từ điểm nhìn C/C++, một bước nhảy khá lớn về độ phức tạp/trừu tượng. Trong số những thứ khác, thêm chi phí này vào mọi đối tượng sẽ làm hỏng một số phương pháp quản lý bộ nhớ được thiết kế để biết kích thước của các đối tượng là gì.