Một ứng dụng thử nghiệm đơn giản:
cout << new int[0] << endl;
đầ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? Có phải luôn luôn hợp pháp để "phân bổ" khối bộ nhớ trống?
Một ứng dụng thử nghiệm đơn giản:
cout << new int[0] << endl;
đầ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? Có phải luôn luôn hợp pháp để "phân bổ" khối bộ nhớ trống?
Câu trả lời:
Từ 5.3.4 / 7
Khi giá trị của biểu thức trong một khai báo trực tiếp mới bằng 0, hàm phân bổ được gọi để phân bổ một mảng không có phần tử.
Từ 3.7.3.1/2
Hiệu quả của việc hủy bỏ hội nghị một con trỏ được trả về như một yêu cầu cho kích thước bằng 0 là không xác định.
Cũng thế
Ngay cả khi kích thước của không gian được yêu cầu [bởi new] bằng 0, 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ả các nền tảng) theo quy định bộ nhớ mà bạn nhận được - bạn chỉ có thể chuyển nó sang xóa mảng - và bạn nên xóa nó.
Dưới đây là một ghi chú thú vị (nghĩa là không phải là một phần quy định của tiêu chuẩn, nhưng được bao gồm cho mục đích lưu trữ) được đính kèm với câu từ 3.7.3.1/2
[32. Mục đích là để toán tử new () có thể thực hiện được bằng cách gọi malloc () hoặc calloc (), vì vậy các quy tắc về cơ bản là giống nhau. C ++ khác với C khi yêu cầu số không yêu cầu trả về con trỏ không null.]
new[]
với delete[]
bất kỳ kích thước nào. Đặc biệt, khi bạn gọi, new[i]
bạn cần thêm một chút bộ nhớ so với mức mà bạn đang cố gắng phân bổ để lưu trữ kích thước của mảng (sau này được sử dụng delete[]
khi xử lý)
Có, việc phân bổ một mảng có kích thước bằng 0 như thế này là hợp pháp. Nhưng bạn cũng phải xóa nó.
int ar[0];
là bất hợp pháp tại sao mới OK?
sizeof (type)
sẽ không bao giờ trở lại số không. Xem ví dụ: stackoverflow.com/questions/2632021/can-sizeof-return-0-zero
Tiêu chuẩn nói gì về điều này? Có phải luôn luôn hợp pháp để "phân bổ" khối bộ nhớ trống?
Mỗi đối tượng có một danh tính duy nhất, tức là một địa chỉ duy nhất, ngụ ý độ dài khác không (lượng bộ nhớ thực tế sẽ được tăng âm thầm, nếu bạn yêu cầu byte không).
Nếu bạn đã phân bổ nhiều hơn một trong những đối tượng này thì bạn sẽ thấy chúng có địa chỉ khác nhau.
operator []
cũng lưu trữ kích thước của mảng ở đâu đó (xem isocpp.org/wiki/faq/freestore-mgmt#num-elems-in-new-array ). Vì vậy, nếu việc triển khai phân bổ số byte bằng dữ liệu, thì nó chỉ có thể phân bổ cho số byte và 0 byte cho dữ liệu, trả về con trỏ 1 quá khứ.
operator new[]
sẽ trả về các con trỏ khác nhau. BTW, new expression
có một số quy tắc bổ sung (5.3.4). Tôi không thể tìm thấy bất kỳ manh mối nào new
với kích thước 0 thực sự cần thiết để phân bổ bất cứ thứ gì. Xin lỗi, tôi đã từ chối 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ố tuyên bố gây tranh cãi.
new[]
triển khai có thể trả về các địa chỉ trong phạm vi không có bộ nhớ động được ánh xạ, do đó không thực sự sử dụng bất kỳ bộ nhớ nào (trong khi sử dụng không gian địa chỉ)
while(!exitRequested) { char *p = new char[0]; delete [] p; }
vòng lặp mà không có con trỏ tái chế sẽ sụp đổ thành bụi trước khi có thể hết không gian địa chỉ, nhưng trên nền tảng có con trỏ 32 bit sẽ là một giả định ít hợp lý.
Có nó là hoàn toàn hợp pháp để phân bổ một 0
khối có 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ạiNULL
.
Bạn vẫn sẽ cần delete []
bất cứ con trỏ nào bạn nhận được từ phân bổ là tốt.
Thật kỳ lạ, C ++ yêu cầu toán tử mới trả về một con trỏ hợp pháp ngay cả khi không có byte nào được yêu cầu. (Yêu cầu hành vi nghe có vẻ kỳ quặc này đơn giản hóa mọi thứ ở nơi khác trong ngôn ngữ.)
Tôi thấy Phiên bản thứ ba hiệu quả của C ++ đã nói như thế này trong "Mục 51: Tuân thủ quy ước khi viết mới và xóa".
Tôi đảm bảo với bạn rằng int [0] mới khiến bạn tốn thêm dung lượng vì tôi đã thử nghiệm nó.
Ví dụ: việc sử dụng bộ nhớ của
int **arr = new int*[1000000000];
nhỏ hơn đáng kể so với
int **arr = new int*[1000000000];
for(int i =0; i < 1000000000; i++) {
arr[i]=new int[0];
}
Việc sử dụng bộ nhớ của đoạn mã thứ hai trừ đi đoạn mã thứ nhất là bộ nhớ được sử dụng cho nhiều int mới [0].