Foo* set = new Foo[100];
// ...
delete [] set;
Bạn không vượt qua ranh giới của mảng delete[]
. Nhưng thông tin đó được lưu trữ ở đâu? Có chuẩn không?
Foo* set = new Foo[100];
// ...
delete [] set;
Bạn không vượt qua ranh giới của mảng delete[]
. Nhưng thông tin đó được lưu trữ ở đâu? Có chuẩn không?
Câu trả lời:
Khi bạn phân bổ bộ nhớ trên heap, bộ cấp phát của bạn sẽ theo dõi lượng bộ nhớ bạn đã phân bổ. Điều này thường được lưu trữ trong một phân đoạn "đầu" ngay trước bộ nhớ mà bạn được phân bổ. Theo cách đó, khi đến lúc giải phóng bộ nhớ, bộ phân bổ biết chính xác dung lượng bộ nhớ còn trống.
free
biết bao nhiêu bộ nhớ để phân bổ". Có, kích thước khối bộ nhớ được lưu trữ "ở đâu đó" bởi malloc
(thông thường trong chính khối đó), vì vậy đó là cách free
biết. Tuy nhiên, new[]
/ delete[]
là một câu chuyện khác nhau. Cái sau về cơ bản hoạt động trên malloc
/ free
. new[]
cũng lưu trữ số lượng phần tử mà nó tạo ra trong khối bộ nhớ (độc lập malloc
), để sau này delete[]
có thể truy xuất và sử dụng số đó để gọi số lượng hàm hủy thích hợp.
malloc
) và số phần tử (theo new[]
). Lưu ý rằng cái trước không thể được sử dụng để tính toán cái sau, vì trong trường hợp chung, kích thước của khối bộ nhớ có thể lớn hơn thực sự cần thiết cho mảng kích thước được yêu cầu. Cũng lưu ý rằng bộ đếm phần tử mảng chỉ cần thiết cho các loại có hàm hủy không tầm thường. Đối với các loại có hàm hủy tầm thường, bộ đếm không được lưu trữ bởi new[]
và, tất nhiên, không được truy xuất bởi delete[]
.
Một trong những cách tiếp cận cho trình biên dịch là phân bổ thêm một chút bộ nhớ và lưu trữ một số phần tử trong phần tử head.
Ví dụ về cách nó có thể được thực hiện:
Đây
int* i = new int[4];
trình biên dịch sẽ phân bổ sizeof(int)*5
byte.
int *temp = malloc(sizeof(int)*5)
Sẽ lưu trữ "4" trong các sizeof(int)
byte đầu tiên
*temp = 4;
và thiết lập i
i = temp + 1;
Vì vậy, i
sẽ chỉ đến một mảng gồm 4 phần tử, không phải 5.
Và xóa
delete[] i;
sẽ được xử lý theo cách sau:
int *temp = i - 1;
int numbers_of_element = *temp; // = 4
... call destructor for numbers_of_element elements
... that are stored in temp + 1, temp + 2, ... temp + 4 if needed
free (temp)
Thông tin không được chuẩn hóa. Tuy nhiên, trong các nền tảng mà tôi đã làm việc với thông tin này được lưu trữ trong bộ nhớ ngay trước phần tử đầu tiên. Do đó về mặt lý thuyết bạn có thể truy cập nó và kiểm tra nó, tuy nhiên nó không đáng.
Ngoài ra, đây là lý do tại sao bạn phải sử dụng xóa [] khi bạn cấp phát bộ nhớ cho [] mới, vì phiên bản mảng xóa biết rằng (và ở đâu) nó cần tìm để giải phóng lượng bộ nhớ phù hợp - và gọi số lượng hàm hủy thích hợp cho các đối tượng.
Về cơ bản, nó được sắp xếp trong bộ nhớ như:
[thông tin] [mem bạn đã yêu cầu ...]
Trong đó thông tin là cấu trúc được trình biên dịch của bạn sử dụng để lưu trữ lượng bộ nhớ được phân bổ và những gì không.
Đây là phụ thuộc thực hiện mặc dù.
Nó được định nghĩa trong tiêu chuẩn C ++ là trình biên dịch cụ thể. Có nghĩa là ma thuật biên dịch. Nó có thể phá vỡ với các hạn chế liên kết không tầm thường trên ít nhất một nền tảng chính.
Bạn có thể suy nghĩ về các triển khai có thể bằng cách nhận ra rằng delete[]
chỉ được xác định cho các con trỏ được trả về bởi new[]
, có thể không phải là con trỏ giống như được trả về bởi operator new[]
. Một cách thực hiện trong tự nhiên là lưu trữ số mảng trong int đầu tiên được trả về bởi operator new[]
và đã new[]
trả về một con trỏ bù qua đó. (Đây là lý do tại sao sự sắp xếp không tầm thường có thể phá vỡ new[]
.)
Hãy ghi nhớ rằng operator new[]/operator delete[]
! = new[]/delete[]
.
Thêm vào đó, đây là trực giao với cách C biết kích thước của bộ nhớ được phân bổ theo malloc
.
Bởi vì mảng được 'xóa' nên đã được tạo bằng một lần sử dụng toán tử 'mới'. Hoạt động 'mới' nên đã đưa thông tin đó vào đống. Nếu không, làm thế nào để sử dụng bổ sung mới biết nơi heap kết thúc?
Nó không được chuẩn hóa. Trong thời gian chạy của Microsoft, toán tử mới sử dụng malloc () và toán tử xóa sử dụng free (). Vì vậy, trong cài đặt này, câu hỏi của bạn tương đương với câu hỏi sau: Làm thế nào để free () biết kích thước của khối?
Có một số sổ sách kế toán đang diễn ra đằng sau hậu trường, tức là trong thời gian chạy C.
Đây là một vấn đề thú vị hơn bạn nghĩ lúc đầu. Câu trả lời này là về một thực hiện có thể.
Đầu tiên, mặc dù ở một mức độ nào đó, hệ thống của bạn phải biết cách 'giải phóng' khối bộ nhớ, malloc / free bên dưới (mà mới / xóa / mới [] / xóa [] thường gọi) không luôn nhớ chính xác bao nhiêu bộ nhớ bạn yêu cầu, nó có thể được làm tròn lên (ví dụ: một khi bạn ở trên 4K, nó thường được làm tròn đến khối có kích thước 4K tiếp theo).
Do đó, ngay cả khi có thể có kích thước của khối bộ nhớ, điều đó không cho chúng ta biết có bao nhiêu giá trị trong bộ nhớ [] ed mới, vì nó có thể nhỏ hơn. Do đó, chúng ta phải lưu trữ một số nguyên phụ cho chúng ta biết có bao nhiêu giá trị.
NGOẠI TRỪ, nếu loại đang được xây dựng không có hàm hủy, thì xóa [] không phải làm gì ngoại trừ giải phóng khối bộ nhớ và do đó không phải lưu trữ bất cứ thứ gì!