2010-03-09 45 views
7

sau một cuộc thảo luận trong một cuộc họp phần mềm tôi đã đặt ra để tìm hiểu xem việc xóa mảng động, được phân bổ nguyên thủy có đồng bằng delete sẽ gây ra rò rỉ bộ nhớ hay không.Xóa p trong đó p là một con trỏ tới mảng luôn luôn bị rò rỉ bộ nhớ?

Tôi đã viết chương trình nhỏ này và biên dịch nó với Visual Studio 2008 chạy trên windows XP:

#include "stdafx.h" 
#include "Windows.h" 

const unsigned long BLOCK_SIZE = 1024*100000; 
int _tmain() 
{ 
    for (unsigned int i =0; i < 1024*1000; i++) 
    { 
     int* p = new int[1024*100000]; 
     for (int j =0;j<BLOCK_SIZE;j++) p[j]= j % 2; 
     Sleep(1000); 
     delete p; 
    } 
} 

tôi hơn giám sát mức tiêu thụ bộ nhớ của ứng dụng của tôi sử dụng task manager, đáng ngạc nhiên bộ nhớ được cấp phát và giải phóng một cách chính xác , bộ nhớ phân bổ không đều đặn tăng như đã được dự kiến ​​

tôi đã sửa đổi chương trình thử nghiệm của tôi để phân bổ một loại nguyên thủy mảng phi:

#include "stdafx.h" 
#include "Windows.h" 


struct aStruct 
{ 
    aStruct() : i(1), j(0) {} 

    int i; 
    char j; 
} NonePrimitive; 

const unsigned long BLOCK_SIZE = 1024*100000; 
int _tmain() 
{ 
    for (unsigned int i =0; i < 1024*100000; i++) 
    { 
     aStruct* p = new aStruct[1024*100000]; 
     Sleep(1000); 
     delete p; 

    } 
} 

sau khi chạy trong 10 phút không có sự gia tăng có ý nghĩa trong bộ nhớ

Tôi đã biên soạn dự án với mức cảnh báo 4 và không có cảnh báo.

có thể là thời gian chạy của studio trực quan theo dõi các loại đối tượng được phân bổ sao cho không có sự khác biệt giữa deletedelete[] trong môi trường đó?

+0

Sao chép? http://stackoverflow.com/questions/1913343/how-could-pairing-new-with-delete-possibly-lead-to-memory-leak-only –

+0

@Philip Potter: Không phải là câu hỏi rất hay - đó là câu hỏi cụ thể về việc gây ra rò rỉ bộ nhớ. Và rò rỉ bộ nhớ không phải là điển hình trong trường hợp này. – sharptooth

+0

Hãy thử nó với một mảng 'shared_ptr ', mỗi trỏ đến một int được phân bổ khác nhau, và bạn sẽ thấy liệu việc triển khai của bạn có làm cho 'delete' và' delete [] 'tương đương hay không. Luôn luôn niềm đam mê này trong C + + với những điều mà mọi người biết là sai, được nêu rõ trong tiêu chuẩn là sai, và chưa xuất hiện như thể họ đôi khi chỉ xảy ra để làm việc ;-) –

Trả lời

19

xóa p, trong đó p là mảng được gọi là hành vi không xác định.

Cụ thể, khi bạn phân bổ một mảng các kiểu dữ liệu thô (ints), trình biên dịch không có nhiều công việc để làm, vì vậy nó biến nó thành một malloc đơn giản(), do đó, xóa p có thể hoạt động.

delete p sẽ thất bại, thông thường, khi:

  • p là một kiểu dữ liệu phức tạp - xóa p; sẽ không biết gọi những người phá hoại riêng lẻ.
  • toán tử quá tải "người dùng" mới [] và xóa [] để sử dụng một vùng heap khác với vùng thông thường.
  • toán tử quá tải thời gian chạy gỡ lỗi mới [] và xóa [] để thêm thông tin theo dõi bổ sung cho mảng.
  • trình biên dịch quyết định cần lưu trữ thông tin RTTI bổ sung cùng với đối tượng, xóa p; sẽ không hiểu, nhưng xóa [] p; sẽ.
17

Không, đó là hành vi không xác định. Đừng làm điều đó - sử dụng delete[].

Trong VC++ 7 đến 9, nó hoạt động when the type in question has trivial destructor, nhưng nó có thể ngừng hoạt động trên các phiên bản mới hơn - thông thường với hành vi không xác định. Đừng làm điều đó.

+0

Giải thích lý do tại sao nó có thể xảy ra để làm việc trong trường hợp của @ Eli! –

2

không, bạn nên sử dụng delete[] khi giao dịch với các mảng

3

Nó được gọi là hành vi undefined; nó có thể hoạt động, nhưng bạn không biết tại sao, vì vậy bạn không nên gắn bó với nó.

Tôi không nghĩ rằng Visual Studio theo dõi cách bạn phân bổ các đối tượng, như mảng hoặc đối tượng đơn giản và thêm kỳ diệu [] vào lần xóa của bạn. Nó có thể biên dịch delete p; thành mã giống như khi bạn phân bổ với p = new int và, như tôi đã nói, vì một số lý do nó hoạt động. Nhưng bạn không biết tại sao.

2

Chỉ cần sử dụng delete sẽ không gọi hàm hủy của đối tượng trong mảng. Trong khi nó sẽ có thể hoạt động như dự định nó không xác định vì có một số khác biệt về chính xác cách chúng hoạt động. Vì vậy, bạn không nên sử dụng nó, even for built in types.

+0

Câu hỏi thường gặp có đối số rất mạnh, cảm ơn vì đã chỉ ra – Eli

1

Lý do dường như không bị rò rỉ bộ nhớ là vì xóa thường dựa trên miễn phí, đã biết bộ nhớ cần bao nhiêu bộ nhớ. Tuy nhiên, phần C++ không thể được dọn dẹp một cách chính xác. Tôi đặt cược rằng chỉ có destructor của đối tượng đầu tiên được gọi.

1

Sử dụng lệnh xóa với [] cho trình biên dịch gọi hàm hủy trên mọi mục của mảng. Không sử dụng xóa [] có thể gây rò rỉ bộ nhớ nếu được sử dụng trên một mảng của các đối tượng sử dụng cấp phát bộ nhớ động như sau:

class AClass 
{ 
public: 
    AClass() 
    { 
     aString = new char[100]; 
    } 
    ~AClass() 
    { 
     delete [] aString; 
    } 
private: 
    const char *aString; 
}; 

int main() 
{ 
    AClass * p = new AClass[1000]; 
    delete p; // wrong 
    return 0; 
} 
3

Một câu trả lời là có, nó có thể gây rò rỉ bộ nhớ, bởi vì nó không gọi destructor cho mọi mục trong mảng. Điều đó có nghĩa rằng bất kỳ bộ nhớ bổ sung thuộc sở hữu của các mục trong mảng sẽ bị rò rỉ.

Câu trả lời tuân thủ tiêu chuẩn hơn là hành vi không xác định. Trình biên dịch, ví dụ, có mọi quyền sử dụng các nhóm bộ nhớ khác nhau cho các mảng hơn là các mục không phải mảng. Làm một cách mới nhưng xóa bỏ các khác có thể gây ra tham nhũng đống.

Trình biên dịch của bạn có thể đảm bảo rằng tiêu chuẩn không, nhưng vấn đề đầu tiên vẫn còn. Đối với các mục POD không sở hữu bộ nhớ bổ sung (hoặc tài nguyên như xử lý tệp), bạn có thể OK.

Thậm chí nếu nó an toàn cho trình biên dịch và các mục dữ liệu của bạn, đừng làm điều đó anyway - nó cũng gây hiểu nhầm cho bất kỳ ai đang cố đọc mã của bạn.

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