2009-07-29 17 views
7

Tại sao mã này không không gây rò rỉ bộ nhớ?std :: auto_ptr, delete [] và rò rỉ

int iterCount = 1000; 
int sizeBig = 100000; 
for (int i = 0; i < iterCount; i++) 
{ 
    std::auto_ptr<char> buffer(new char[sizeBig]); 
} 

WinXP sp2, biên dịch: BCB.05.03

+0

Trong hầu hết các trường hợp, nếu bạn ghép nối mới với xóa [] và ngược lại với các loại không tầm thường thì điều này không gây ra rò rỉ - thay vào đó chương trình chỉ đơn giản là treo khi cố gắng xử lý bộ nhớ. – sharptooth

+3

Bạn có thể thử sử dụng boost :: scoped_array thay vì std :: auto_ptr –

Trả lời

15

Bởi vì bạn (un) may mắn. auto_ptr gọi delete, không phải delete []. Đây là hành vi không xác định.

Hãy thử làm một cái gì đó như thế này và xem liệu bạn có được may mắn như:

struct Foo 
{ 
    char *bar; 
    Foo(void) : bar(new char[100]) { } 
    ~Foo(void) { delete [] bar; } 
} 

int iterCount = 1000; 
int sizeBig = 100000; 
for (int i = 0; i < iterCount; i++) 
{ 
    std::auto_ptr<Foo> buffer(new Foo[sizeBig]); 
} 

Ý tưởng ở đây là destructor của bạn cho Foo sẽ không được gọi.


Lý do là một cái gì đó như thế này: Khi bạn nói delete[] p, việc thực hiện delete[] là giả sử để đi đến từng phần tử trong mảng, gọi destructor của nó, sau đó giải phóng bộ nhớ được trỏ đến bởi p. Tương tự, delete p giả sử gọi hàm hủy trên p, sau đó giải phóng bộ nhớ.

char không có trình phá hủy, do đó, nó sẽ xóa bộ nhớ được trỏ tới bởi p. Trong mã của tôi ở trên, nó là không sẽ hủy mỗi phần tử trong mảng (vì nó không gọi delete[]), do đó, một số Foo sẽ để biến thanh địa phương của chúng chưa được xóa.

+0

Có, tôi không may mắn :) Cảm ơn bạn đã giải thích. – Xeningem

+0

Tôi đã biên dịch nhưng tôi nhận được thông báo lỗi '_BLOCK_TYPE_IS_VALID (pHead-> nBlockUse)', chương trình bị treo ..điều này dường như chỉ ra rằng nó đang bị xóa hai lần nhưng không biết làm thế nào mà có thể xảy ra – zar

+0

Các destructor của 'Foo' trong thực tế sẽ được gọi là 'iterCount'times nhưng lưu ý' iterCount' * 'sizeBig' lần – zar

3

Auto_ptr sẽ chỉ hoạt động trong khoảng thời gian lặp vòng lặp và sẽ giải phóng đối tượng được kết nối với nó khi hoàn thành lặp lại.

Trình biên dịch có thể thấy rằng trong trường hợp này mới [] có thể phân bổ không gian trong cùng một cách như mới - mà không cần lưu trữ các số nguyên tố bất cứ nơi nào vì không có nhu cầu gọi tầm thường char destructors - và đó là lý do tại sao sau khi xóa được gọi bởi destructor của auto_ptr thay vì xóa [] nó gây ra không có vấn đề kể từ khi khối bộ nhớ đã thực sự được phân bổ trong mới cách 's và phân bổ có thể được kết hợp với xóa.

Đây là ví dụ về một điều không nên làm. Tùy thuộc vào trình biên dịch để quyết định có thay thế mới [] bằng mới hay không. Sử dụng xóa thay vì xóa [] và ngược lại là hành vi không xác định.

Xem Why would you write something like this? (intentionally not using delete [] on an array) để thảo luận về xóa vs xóa [].

+0

Vì vậy, như GMan nói: may mắn thay * xóa * tương đương với * xóa [] * ở đây? – xtofl

+1

Vâng, vâng, đó là kết quả của trình biên dịch cố gắng tiết kiệm thông minh và tiết kiệm tai nạn cho nhà phát triển. – sharptooth

+3

Nó không phải là kết quả của trình biên dịch thông minh, nó là kết quả của trình biên dịch được lười biếng và làm điều dễ nhất (trong trường hợp này có nghĩa là cấp phát bộ nhớ cho một phần tử và mảng khi POD được tham gia hoạt động chính xác như nhau). Tất nhiên đây là U.B., do đó, nó là "tuyệt may mắn" mà nó hoạt động trong một thực hiện nhất định - và IIRC có một số triển khai thực sự mà nó không hoạt động. –

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