2009-07-06 4 views
190

Một đơn giản ứng dụng thử nghiệm:C++ new int [0] - nó sẽ cấp phát bộ nhớ?

cout << new int[0] << endl; 

kết quả đầu ra:

0x876c0b8 

Vì vậy, nó trông giống như nó hoạt động. Tiêu chuẩn nói gì về điều này? Nó luôn luôn là hợp pháp để "phân bổ" khối trống của bộ nhớ?

+3

+1 Câu hỏi rất thú vị - mặc dù tôi không chắc là nó quan trọng đến mức nào trong mã thực. – Zifre

+23

@Zifre: Tôi yêu cầu sự tò mò, nhưng nó có thể quan trọng trong thế giới thực, ví dụ: khi kích thước của khối bộ nhớ được phân bổ được tính theo một cách nào đó, và kết quả của phép tính có thể bằng 0, thì không cần phải thêm ngoại lệ để không phân bổ khối có kích thước bằng 0 .. Vì chúng phải được cấp phát và xóa mà không có lỗi (nếu chỉ khối có kích thước bằng 0 không bị hủy tham chiếu). Vì vậy, nói chung điều này cho phép trừu tượng hóa rộng hơn về khối bộ nhớ. –

+2

@ emg-2: Trong trường hợp ví dụ của bạn, nó thực sự sẽ không quan trọng, bởi vì xóa [] là hoàn toàn hợp pháp trên một con trỏ NULL :-). –

Trả lời

198

Từ 5.3.4/7

Khi giá trị của biểu thức trong một-mới-declarator trực tiếp là zero, chức năng phân bổ được gọi là phân bổ một mảng không có yếu tố này.

Từ 3.7.3.1/2

Hiệu quả của dereferencing một con trỏ trở lại như một yêu cầu kích thước bằng không là không xác định.

Cũng

Thậm chí nếu kích thước của không gian yêu cầu [do mới] là số không, yêu cầu có thể thất bại.

Điều đó có nghĩa là bạn có thể làm điều đó, nhưng bạn không thể hợp pháp (theo cách được xác định rõ ràng trên tất cả nền tảng).

Dưới đây là một thú vị chân-note (nghĩa là không phải là một phần bản quy phạm tiêu chuẩn, nhưng bao gồm cho mục đích bình luận) gắn liền với câu từ 3.7.3.1/2

[32. Mục đích là để có toán tử new() có thể thực hiện được bằng cách gọi hàm malloc() hoặc calloc(), vì vậy các quy tắc đều giống nhau. C++ khác với C trong đòi hỏi một yêu cầu không để trả về một con trỏ null.]

+3

+1 để trích dẫn tiêu chuẩn! – Nav

+0

Tôi bị rò rỉ bộ nhớ nếu tôi không xóa. Nó được mong đợi? Ít nhất là tôi không mong đợi. – EralpB

+8

@EralpB: ngược lại, ngay cả khi yêu cầu của bạn bằng 0, phân bổ này xảy ra trên Heap, trong đó một yêu cầu ngụ ý một số hoạt động lưu trữ sách, như phân bổ và khởi tạo bảo vệ heap trước và sau vùng được cấp bởi người cấp phát. hoặc các cấu trúc khủng khiếp phức tạp khác. Giải phóng nó có nghĩa là làm sổ sách kế toán lạc hậu. –

19

Có, đó là hợp pháp để phân bổ một mảng có kích cỡ bằng không như thế này. Nhưng bạn cũng phải xóa nó.

+1

Bạn có một trích dẫn cho điều này? Chúng ta đều biết rằng 'int ar [0]; 'là bất hợp pháp tại sao OK mới? – Motti

+0

Xem câu trả lời của Faisal. –

+4

Điều thú vị là C++ không quá mạnh với việc cấm các đối tượng có kích thước bằng không. Hãy suy nghĩ về tối ưu hóa lớp cơ sở trống: Ở đây cũng vậy, một đối tượng phụ lớp cơ sở trống có thể có kích thước bằng không. Ngược lại, tiêu chuẩn C tạo ra một nỗ lực mạnh mẽ để đảm bảo không bao giờ có các đối tượng có kích thước bằng không được tạo ra: Trong việc định nghĩa malloc (0) nó cho biết hiệu ứng là chạy malloc với một số đối số khác 0 chẳng hạn. Và trong struct {...; T n []; }; khi không có không gian được phân bổ cho mảng (FAM), nó nói nó hoạt động như thể "n" có một phần tử. (Trong cả hai trường hợp, sử dụng đối tượng theo bất kỳ cách nào là UB, như x.n [0]) –

11

Có nó là hoàn toàn hợp pháp để phân bổ một 0 khối kích thước với new. Bạn chỉ đơn giản là không thể làm bất cứ điều gì hữu ích với nó vì không có dữ liệu hợp lệ để bạn truy cập. int[0] = 5; là bất hợp pháp.

Tuy nhiên, tôi tin rằng tiêu chuẩn cho phép những thứ như malloc(0) trả lại NULL.

Bạn vẫn cần phải delete [] bất kỳ con trỏ nào bạn cũng nhận được từ phân bổ.

+5

Về malloc, bạn đúng - đó là việc thực hiện được xác định. Điều này thường được xem là một sự không hài lòng. –

+0

Tôi cho rằng một câu hỏi thú vị là: có thể phiên bản nothrow của NULL trả về mới nếu có kích thước bằng 0 không? –

+1

Ngữ nghĩa của mới và malloc không được liên kết theo bất kỳ cách nào, ít nhất là theo tiêu chuẩn. –

14

Tiêu chuẩn nói gì về điều này? Nó luôn luôn là hợp pháp để "phân bổ" khối trống của bộ nhớ?

Mọi đối tượng đều có một nhận dạng duy nhất, tức là một địa chỉ duy nhất, có nghĩa là độ dài khác 0 (số lượng bộ nhớ thực sẽ tăng âm thầm nếu bạn yêu cầu 0 byte).

Nếu bạn phân bổ nhiều hơn một trong các đối tượng này thì bạn sẽ thấy chúng có địa chỉ khác nhau.

+0

"Mọi đối tượng đều có một định danh duy nhất, tức là một địa chỉ duy nhất, ngụ ý một chiều dài khác 0" - đúng, nhưng sai. Đối tượng có địa chỉ, nhưng con trỏ đến đối tượng có thể trỏ đến bộ nhớ ngẫu nhiên. "Số lượng bộ nhớ thực tế sẽ được tăng âm thầm, nếu bạn yêu cầu không có byte" - không chắc chắn. 'operator []' cũng lưu trữ kích thước của mảng ở đâu đó (xem https://isocpp.org/wiki/faq/freestore-mgmt#num-elems-in-new-array). Vì vậy, nếu việc thực hiện phân bổ số byte với dữ liệu, nó có thể chỉ phân bổ cho số byte và 0 byte cho dữ liệu, trả về con trỏ 1-qua-cuối cùng. – Steed

+0

Độ dài không khác của bộ nhớ được cấp phát, không phải là độ dài không sử dụng của bộ nhớ có thể sử dụng. Quan điểm của tôi là hai con trỏ tới hai đối tượng riêng biệt không nên trỏ đến cùng một địa chỉ. – ChrisW

+1

Tiêu chuẩn (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf) thực sự nói (3.7.4.1/2) rằng các cuộc gọi khác nhau tới toán tử mới [ ] 'nên trả về các con trỏ khác nhau. BTW, 'biểu thức mới' có một số quy tắc bổ sung (5.3.4). Tôi không thể tìm thấy bất kỳ đầu mối nào 'mới' có kích thước 0 thực sự là _required_ để phân bổ bất kỳ thứ gì. Xin lỗi, tôi đã bỏ phiếu vì tôi thấy rằng câu trả lời của bạn không trả lời các câu hỏi, nhưng đang cung cấp một số câu nói gây tranh cãi. – Steed

-1

Thật kỳ lạ, C++ yêu cầu toán tử mới trả lại con trỏ hợp lệ ngay cả khi không yêu cầu byte. (. Yêu cầu lạ thường hành vi này giúp đơn giản hoá mọi thứ ở nơi khác trong ngôn ngữ)

tôi thấy Effective C++ Third Edition nói như thế này trong "Item 51: Tuân thủ Công ước khi viết mới và xóa".