2013-07-12 29 views
7

Nếu chúng ta phân bổ một đối tượng có kích thước 1 như sauTôi có thể sử dụng `toán tử xóa []` để phân bổ mảng phần tử đơn lẻ không?

int *arr = new int[1]; 

Chúng ta có nên xóa các đối tượng sử dụng operator delete[] hoặc operator delete?

Lý do tôi quan tâm là nếu trình biên dịch đủ thông minh để chuyển đổi câu lệnh dưới dạng phân bổ phần tử đơn lẻ int *arr = new int, điều này sẽ gây ra việc gọi số operator delete[] UB.

Trường hợp người dùng:

Tôi có một con trỏ, thứ mà tôi sẽ phân bổ theo nhiều cách khác nhau nhưng cuối cùng cũng muốn xóa nó. Vì vậy, đã tự hỏi, đối với việc phân bổ các yếu tố duy nhất, nếu tôi liên tục sử dụng int *arr = new int[1] tôi có thể liên tục và an toàn sử dụng operator delete[]

Note

Bạn có thể vui lòng tham khảo tôi trở lại với các tiêu chuẩn để hỗ trợ câu trả lời của bạn?

+5

'toán tử xóa []' tất nhiên. 'int [1]' không phải là 'int'. Trình biên dịch * đủ thông minh * sẽ không chuyển đổi câu lệnh. – johnchen902

+2

Đó là cùng một vị trí trong tiêu chuẩn cho phép bạn gọi 'delete []' sau 'new [] '. không có trường hợp đặc biệt nào cho kích thước 1. – juanchopanza

+1

* Nếu * trình biên dịch * đủ thông minh để làm điều đó (mặc dù thay đổi một kiểu khác không liên quan gì đến thông minh), nó sẽ phải thông báo cho bạn về điều này thay đổi hoặc thay đổi này sẽ phải được xác định trong tiêu chuẩn và trong trường hợp này, nó cũng sẽ không thông minh, nhưng bắt buộc. Nếu nó âm thầm sau lưng thì trình biên dịch đó không thông minh nhưng * cố ý xấu xa *. Không cần cho bất kỳ tài liệu chuẩn nào ngoài dạng thức thông thường, một 'int' chỉ * không giống * như một' int [1] '. Là một mảng một phần tử vẫn là một mảng (gợi ý: câu trả lời ẩn trong bình luận này)? –

Trả lời

13

Bạn phải sử dụng delete[] và không phải delete. Trình biên dịch không được phép thay đổi new int[1] thành new int.

(Như int là một loại POD nó khá có thể là new intnew int[1] thực hiện chính xác những điều tương tự theo bao, nhưng nếu đây là trường hợp sau đó delete[] trên và int*delete trên một int* cũng sẽ làm chính xác những điều tương tự .)

ISO/IEC 14882: 2011 5.3.5 [expr.delete]/2:

trong phương án đầu tiên (đối tượng xóa), giá trị của toán hạng của delete có thể là giá trị con trỏ null, con trỏ tới đối tượng không mảng được tạo bởi một biểu thức mới mới hoặc con trỏ tới một đối tượng con (1.8) đại diện cho lớp cơ sở của đối tượng như vậy (Điều 10). Nếu không, hành vi là không xác định.

Như int[1] là một đối tượng mảng, nếu bạn cố gắng và xóa nó với delete và không delete[], hành vi này là không xác định.

+0

Bạn có thể giới thiệu lại cho tôi các tiêu chuẩn không? – Abhijit

+0

@Abhijit: Nó không được nêu trong tiêu chuẩn, vì vậy tôi không thể cung cấp cho bạn một số phần, nhưng vì lý do tương tự, nó không được phép. – MSalters

+0

Ngoài các hạn chế * xóa biểu thức *, có các hạn chế đối với chức năng deallocation của Thư viện Chuẩn: "Nếu không, hành vi sẽ không được xác định nếu giá trị được cung cấp cho' toán tử xóa (void *) 'trong thư viện chuẩn không phải là một trong các giá trị được trả về bởi lệnh gọi trước của toán tử 'new (std :: size_t)' hoặc toán tử 'new (std :: size_t, const std :: nothrow_t &)' trong thư viện chuẩn [...] "(+ the tương tự cho phân bổ mảng (de)) [basic.stc.dynamic.deallocation]/3 – dyp

2

Chúng tôi có nên xóa đối tượng bằng cách sử dụng toán tử delete[] hoặc operator delete?

operator delete[]. Bạn đã phân bổ một mảng trong số int giây, do đó không có tùy chọn nào khác để xử lý chính xác nó. Sử dụng operator delete sẽ gọi hành vi không xác định.

6

Quy tắc là khá đơn giản:

  1. luôn cân bằng một new với một delete
  2. luôn cân bằng một new[] với một delete[]

nếu không bạn có được hành vi undefined.

không có ngoại lệ; thậm chí new[1] phải được cân bằng với delete[]new[0] phải bị xóa vì trình biên dịch vẫn có thể đặt trước bộ nhớ.

+2

IIRC, 'new [0]' không được cho phép. – chris

+0

IIRC? Cái gì? – Bathsheba

+1

Nếu tôi nhớ chính xác. Tôi không thấy bất cứ điều gì từ một quét tiêu chuẩn nhanh chóng, mặc dù, vì vậy có lẽ tôi nhớ sai hoặc chạy vào một lỗi trình biên dịch bị lỗi, hoặc có lẽ tôi đã suy nghĩ của một mảng bình thường. – chris

2

Bạn phải sử dụng delete[].

C++ 11 5.3.5 Xóa

:: chọn xóa đúc biểu

:: chọn delete [] đúc thể hiện

Giải pháp thay thế đầu tiên là dành cho phi mảng các đối tượng và thứ hai là dành cho mảng.

Mảng giữ một phần tử vẫn là một mảng.

1
int *arr = new int[1]; 

Vì bạn sử dụng [] phân bổ, bạn cần phải sử dụng [] cho delete là tốt.

Memory leaks

Đối tượng được tạo ra bởi các biểu thức mới (đối tượng với thời gian lưu trữ động) kéo dài cho đến khi con trỏ trả về bởi các biểu hiện mới là sử dụng trong một phù hợp với xóa biểu hiện.

Vì vậy, bạn nên sử dụng delete[] để giải phóng bộ nhớ hoặc cách khác bạn nhận được hành vi không xác định.

(trong trường hợp), nếu trình biên dịch là đủ thông minh để có int * arr = new int[1] như int, Nó phải đủ thông minh để có delete[] arr trên arr như delete arr. Tuy nhiên, không có gì cho delete để phân biệt giữa arr từ int*arr = new int[1]int*arr = new int. [] in delete sẽ cho biết.

0

Không an toàn, điều này có thể dẫn đến một số tình huống không mong muốn.
Ví dụ: Có thể trong bộ nhớ có một số dữ liệu (int/char/float ...) bên cạnh vị trí mà con trỏ trỏ đến. Vào thời điểm đó nếu bạn đã sử dụng delete [] thì có thể cố gắng xóa dữ liệu đó nếu đó là số nguyên, đối với các loại dữ liệu khác dẫn đến lỗi không mong muốn.

Ví dụ:

int *ptr = new int; 
int a = 20; 
char c = 'e'; 
*ptr = 10; 
delete [] ptr; 

Có một khả năng các ca biến có thể lưu trữ bên cạnh vị trí nơi con trỏ ptr điểm đến, Nếu a được lưu trữ bên cạnh nó, sau đó nó xóa "a "Ngoài ra, nếu các kiểu dữ liệu khác có mặt, dẫn đến kết quả thời gian chạy không mong muốn.

Vì vậy, khuyên bạn chỉ nên sử dụng delete[] chỉ để xóa bộ nhớ được cấp phát bằng cách sử dụng kiểu dữ liệu mới []. Hy vọng điều này hữu ích.

+0

Làm cách nào để phân bổ các biến được phân bổ kết thúc bên cạnh các biến được cấp phát? Làm cách nào bạn nghĩ ra "khả năng" đó? Vui lòng không viết thư chỉ vì mục đích viết. –

Các vấn đề liên quan