xóa vs xóa toán tử [] trong C ++


134

Sự khác biệt giữa deletedelete[]toán tử trong C ++ là gì?


Bạn có thể tìm thấy câu hỏi này có liên quan stackoverflow.com/questions/1913343/ từ
sharptooth

7
Các vấn đề với xóa và xóa [] là một lý do tại sao tôi thích con trỏ thông minh và sử dụng vector<>thay vì một mảng bất cứ khi nào tôi có thể.
David Thornley


@DavidThornley Nếu bạn đang sử dụng con trỏ thông minh, bạn vẫn cần biết sự khác biệt theo nghĩa mà bạn vẫn cần biết không viết std::unique_ptr<int>(new int[3]), ví dụ: bởi vì nó sẽ gọi thường xuyên deletetrên mảng là hành vi không xác định. Thay vào đó bạn cần sử dụngstd::unique_ptr<int[]>
Arthur Tacca

Câu trả lời:


149

Các deletenhà điều hành deallocates bộ nhớ và gọi destructor cho một đối tượng duy nhất được tạo ra với new.

Các delete []nhà điều hành deallocates hủy bộ nhớ và các cuộc gọi cho một mảng của các đối tượng được tạo ra với new [].

Sử dụng deletetrên một con trỏ được trả về bởi new []hoặc delete []trên một con trỏ được trả về bởi các newkết quả trong hành vi không xác định.


3
Tôi tự hỏi nếu sử dụng xóa trên một mảng [] mới của các kiểu nguyên thủy như int hoặc char (không có hàm tạo / hàm hủy) cũng nhất thiết dẫn đến hành vi không xác định. Có vẻ như kích thước mảng không được lưu trữ ở bất cứ đâu khi sử dụng các kiểu nguyên thủy.
thomiel

21
Nếu tiêu chuẩn không xác định điều gì xảy ra khi điều đó được thực hiện, thì đó là theo định nghĩa "hành vi không xác định", ngay cả khi trình biên dịch của bạn xác định rõ ràng bạn muốn làm gì. Một trình biên dịch khác có thể làm một cái gì đó hoàn toàn khác nhau.
Rob K

Tôi đã mắc lỗi này khi tôi có một chuỗi các chuỗi C như "char ** strArray". Nếu bạn có một mảng như tôi làm, bạn cần lặp lại qua mảng và xóa / giải phóng từng phần tử, sau đó xóa / giải phóng strArray. Sử dụng "xóa []" trên mảng mà tôi không hoạt động kể từ (như được chỉ ra bởi các nhận xét và câu trả lời ở trên), IT GỌI GỌI GỌI, nó thực sự không giải phóng từng vị trí.
Katianie

88

Các delete[]nhà điều hành được sử dụng để mảng xóa. Các deletenhà điều hành được sử dụng để xóa các đối tượng không cho mảng. Nó gọi operator delete[]operator deletehàm tương ứng để xóa bộ nhớ mà đối tượng mảng hoặc không phải mảng chiếm sau (cuối cùng) gọi các hàm hủy cho các phần tử của mảng hoặc đối tượng không phải là mảng.

Sau đây cho thấy các mối quan hệ:

typedef int array_type[1];

// create and destroy a int[1]
array_type *a = new array_type;
delete [] a;

// create and destroy an int
int *b = new int;
delete b;

// create and destroy an int[1]
int *c = new int[1];
delete[] c;

// create and destroy an int[1][2]
int (*d)[2] = new int[1][2];
delete [] d;

Đối với việc newtạo ra một mảng (vì vậy, new type[]hoặc newđược áp dụng cho cấu trúc kiểu mảng), Tiêu chuẩn tìm kiếm một operator new[]loại lớp phần tử của mảng hoặc trong phạm vi toàn cầu và chuyển lượng bộ nhớ được yêu cầu. Nó có thể yêu cầu nhiều hơn N * sizeof(ElementType)nếu nó muốn (ví dụ để lưu trữ số lượng phần tử, vì vậy sau này khi xóa sẽ biết có bao nhiêu lệnh gọi hàm hủy được thực hiện). Nếu lớp khai báo operator new[]thêm một lượng bộ nhớ chấp nhận một bộ nhớ khác size_t, tham số thứ hai đó sẽ nhận được số phần tử được phân bổ - nó có thể sử dụng điều này cho bất kỳ mục đích nào nó muốn (gỡ lỗi, v.v.).

Đối với việc newtạo ra một đối tượng không phải là mảng, nó sẽ tìm kiếm một lớp operator newtrong phần tử hoặc trong phạm vi toàn cục. Nó vượt qua số lượng bộ nhớ được yêu cầu (chính xác sizeof(T)luôn luôn).

Đối với delete[], nó nhìn vào loại lớp phần tử của mảng và gọi các hàm hủy của chúng. Các operator delete[]chức năng được sử dụng là một trong lớp các loại nguyên tố, hoặc nếu không có thì trong phạm vi toàn cầu.

Đối với delete, nếu con trỏ được truyền là một lớp cơ sở của loại đối tượng thực tế, thì lớp cơ sở phải có một hàm hủy ảo (nếu không, hành vi không được xác định). Nếu nó không phải là một lớp cơ sở, thì hàm hủy của lớp đó được gọi và một operator deletetrong lớp đó hoặc toàn cục operator deleteđược sử dụng. Nếu một lớp cơ sở được thông qua, thì hàm hủy của loại đối tượng thực tế được gọi và operator deletetìm thấy trong lớp đó được sử dụng hoặc nếu không có, thì toàn cục operator deleteđược gọi. Nếu operator deletetrong lớp có một tham số thứ hai của loại size_t, nó sẽ nhận được số lượng phần tử để phân bổ.


18

Đây là cách sử dụng cơ bản của mẫu phân bổ / DE-phân bổ trong c ++ malloc/ free, new/ delete, new[]/delete[]

Chúng ta cần sử dụng chúng tương ứng. Nhưng tôi muốn thêm sự hiểu biết đặc biệt này cho sự khác biệt giữa deletedelete[]

1) deleteđược sử dụng để phân bổ lại bộ nhớ được phân bổ cho một đối tượng

2) delete[]được sử dụng để phân bổ lại bộ nhớ được phân bổ cho mảng các đối tượng

class ABC{}

ABC *ptr = new ABC[100]

Khi chúng ta nói new ABC[100], trình biên dịch có thể nhận được thông tin về số lượng đối tượng cần được phân bổ (ở đây là 100) và sẽ gọi hàm tạo cho mỗi đối tượng được tạo

nhưng tương ứng nếu chúng ta chỉ đơn giản sử dụng delete ptrcho trường hợp này, trình biên dịch sẽ không biết có bao nhiêu đối tượng ptrđang trỏ đến và sẽ kết thúc việc gọi hàm hủy và xóa bộ nhớ chỉ cho 1 đối tượng (để lại lệnh gọi hàm hủy và xử lý 99 đối tượng còn lại). Do đó sẽ có một rò rỉ bộ nhớ.

vì vậy chúng ta cần sử dụng delete [] ptrtrong trường hợp này


3
Đây phải là câu trả lời chính xác. Không có câu trả lời nào khác đề cập đến sự khác biệt rõ ràng: "nhưng tương ứng nếu chúng ta chỉ đơn giản sử dụng xóa ptr cho trường hợp này, trình biên dịch sẽ không biết có bao nhiêu đối tượng mà ptr đang trỏ đến và sẽ kết thúc việc gọi hàm hủy và xóa bộ nhớ chỉ cho 1 đối tượng"
Don Larynx

1
Làm thế nào để chúng ta đạt được điều tương tự trong C?
Dogus Ural

@DogusUral Tại sao? Không có hàm hủy trong C, vì vậy bạn chỉ free()cái này và cái kia. Nếu bạn sử dụng mô hình giả hủy, bạn phải gọi nó một lần cho mọi đối tượng bằng forvòng lặp.
Kotauskas

@DonLarynx sự khác biệt chính xác là trộn chúng lại dẫn đến một chương trình không đúng định dạng. Một triển khai có thể biết bao nhiêu đối tượng để phá hủy, hoặc nó có thể không . Nó được phép biết rằng nó được gọi là sai và hủy bỏ chương trình cho bạn biết vấn đề đang ở đâu.
Caleth

6

Các toán tử deletedelete []được sử dụng tương ứng để phá hủy các đối tượng được tạo bằng newnew[], trở về bộ nhớ được phân bổ còn lại cho trình quản lý bộ nhớ của trình biên dịch.

Các đối tượng được tạo bằng newnhất thiết phải được hủy bằng deletevà các mảng được tạo bằng new[]phải được xóa bằng delete[].


2

Khi tôi hỏi câu hỏi này, câu hỏi thực sự của tôi là "có sự khác biệt nào giữa hai câu hỏi không? Thời gian chạy không phải giữ thông tin về kích thước mảng, và vì vậy nó sẽ không thể nói chúng ta muốn nói gì?" Câu hỏi này không xuất hiện trong "các câu hỏi liên quan", vì vậy chỉ để giúp đỡ những người như tôi, đây là câu trả lời cho điều đó: "tại sao chúng ta thậm chí cần toán tử xóa []?"


Cảm ơn bạn đã quay lại và đưa cái này vào.
Ziffusion

0

deleteđược sử dụng cho một con trỏ và delete[]được sử dụng để xóa một mảng thông qua một con trỏ. Điều này có thể giúp bạn hiểu rõ hơn.


-6

Chà .. có lẽ tôi nghĩ nó chỉ dành cho rõ ràng. Toán tử deletevà toán tử delete[]được phân biệt nhưng deletetoán tử cũng có thể giải phóng mảng.

test* a = new test[100];
delete a;

Và đã kiểm tra mã này không có rò rỉ memeory.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.