2011-12-16 4 views
6

Hãy xem xét các chương trình sau đây:Khi nào thì một đối tượng trên heap đi ra khỏi phạm vi

int main() { 

    while(...) { 
     int* foobar = new int; 
    } 

    return 0; 
} 

Khi nào foobar đi ra khỏi phạm vi?

Tôi biết khi sử dụng new, thuộc tính được phân bổ trên heap và cần phải được xóa theo cách thủ công với delete, trong đoạn mã trên, nó gây ra rò rỉ bộ nhớ. Tuy nhiên, những gì về phạm vi?

Tôi nghĩ rằng nó sẽ đi ra khỏi phạm vi ngay sau khi vòng lặp while chấm dứt, bởi vì bạn không có quyền truy cập trực tiếp vào nó nữa. Ví dụ: bạn không thể delete sau khi vòng lặp kết thúc.

+0

Đây là khó khăn, bởi vì 'foobar' là một con trỏ, mà chính xác đi ra khỏi phạm vi và nó bị phá hủy (nhưng đối tượng nó trỏ vào là _not_ deallocated). 'Int' là một đối tượng trên heap, không có phạm vi, và vì bạn không có lệnh' delete', nó bị rò rỉ. –

Trả lời

13

Hãy cẩn thận ở đây, foobar là địa phương trong vòng lặp while, nhưng phân bổ trên heap không có phạm vi và sẽ chỉ bị hủy nếu bạn gọi xóa trên đó.

Biến và phân bổ không được liên kết theo bất kỳ cách nào liên quan đến trình biên dịch. Thật vậy, phân bổ xảy ra tại thời gian chạy, vì vậy trình biên dịch thậm chí không bao giờ nhìn thấy nó.

+3

Tôi khuyên bạn nên 'std :: unique_ptr ' –

+7

@MooingDuck: Tôi khuyên bạn nên 'int' ;-p –

+7

@SteveJessop: Một' int' một ngày giữ con trỏ đi ... –

2

Con trỏ (foobar) sẽ đi ra khỏi phạm vi ngay khi chương trình nhận được dấu ngoặc đóng của vòng lặp while. Vì vậy, nếu biểu thức trong các ... vẫn đúng, bộ nhớ sẽ bị rò rỉ mỗi khi vòng lặp thực hiện khi bạn đã mất một xử lý đối tượng được phân bổ như của cú đúp đóng.

+1

bạn sử dụng 'nó' và' biến đó', mà không cần làm rõ. Con trỏ đi ra khỏi phạm vi, con trỏ/đối tượng sẽ bị rò rỉ, bởi vì nó không có phạm vi. –

+0

Hỏi: "Khi nào foobar đi ra khỏi phạm vi?", A: "Nó sẽ đi ra khỏi phạm vi ..." Tôi rõ ràng đang nói về foobar. Biến duy nhất trong câu hỏi là foobar, pointee/object không phải là một biến. Cập nhật bất kể ... –

+0

Trong khi câu trả lời là chính xác, nó đã gây hiểu lầm vì OP rõ ràng không phân biệt được giữa con trỏ và con trỏ. –

0

Vì foobar được khai báo trong phần thân của vòng lặp, nó vượt quá phạm vi vào cuối mỗi lần lặp của vòng lặp. Sau đó nó được redeclared, và bộ nhớ mới được phân bổ một lần nữa và một lần nữa cho đến khi vòng lặp kết thúc. Đối tượng thực tế mà foobar trỏ đến không bao giờ nằm ​​ngoài phạm vi. Phạm vi không áp dụng cho các đối tượng được phân bổ động (aka heap), chỉ cho các đối tượng tự động (stack).

0

foobar vượt quá phạm vi sau mỗi lần liên kết vòng lặp.

Bộ nhớ bạn cấp phát và gán cho foobar đang bị rò rỉ, trong đó nó vẫn được cấp phát trên heap nhưng không có tham chiếu đến nó có sẵn trong chương trình.

9

là một biến cục bộ nằm ngoài phạm vi của khối.

*foobar là đối tượng được phân bổ động với thời lượng thủ công. Vì nó không có thời gian tồn tại của phạm vi, câu hỏi không có ý nghĩa gì - nó không phạm vi mà nó có thể đi. Tuổi thọ của nó được quản lý theo cách thủ công và đối tượng sống cho đến khi bạn delete nó.

Câu hỏi của bạn được gánh nặng một cách nguy hiểm với định kiến ​​và định kiến. Tốt nhất là tiếp cận C++ với một tâm trí sạch sẽ và thái độ cởi mở. Chỉ bằng cách đó bạn sẽ có thể đánh giá cao những kỳ quan của ngôn ngữ với đầy đủ nhất.


Dưới đây là cách tiếp cận sạch và cởi mở: Đừng suy nghĩ về 1) lớp lưu trữ (tự động, tĩnh, động), 2) đối tượng suốt đời (scoped, vĩnh viễn, bằng tay), 3) ngữ nghĩa đối tượng (giá trị (bản sao) so với tham chiếu (bí danh)), 4) RAII và các lớp đơn có trách nhiệm.Gột rửa tâm trí của bạn của a) stack/đống, b) con trỏ, c) các nhà khai thác mới/xóa, d) destructors/nhà thầu sao chép/chuyển nhượng.

+0

Bạn không thể hoàn toàn thanh tẩy tâm trí của bạn về các toán tử gán, bởi vì ngay cả khi bạn nhận được mọi thứ đúng đắn, bạn phải rõ ràng 'mặc định' ctor di chuyển và chuyển nhượng cho các lớp giá trị ngữ nghĩa của bạn :-) –

+1

+1 cho sạch và cách tiếp cận mở, mặc dù nó phải ở phông chữ lớn hơn thay vì nhỏ hơn ;-P – AJG85

+1

@SteveJessop: Thứ tự đứng là, như mọi khi: Một khi bạn hiểu tại sao bạn có thể bỏ qua lời khuyên, an toàn để bỏ qua lời khuyên :-) (Mặc dù nếu bạn không khai báo * bất cứ điều gì *, bạn sẽ nhận được các ngữ nghĩa di chuyển tối ưu nhất một cách tự động, không?) –

3

Đó là một lỗ hổng bộ nhớ khá tuyệt vời. Bạn có một biến trên ngăn xếp trỏ đến bộ nhớ được phân bổ trên heap. Bạn cần phải xóa bộ nhớ trên heap trước khi bạn mất tham chiếu đến nó khi phạm vi vòng lặp while kết thúc. Cách khác, nếu bạn không muốn phiền phức với quản lý bộ nhớ, hãy luôn sử dụng con trỏ thông minh để sở hữu bộ nhớ thô trên heap và để nó tự làm sạch.

#include <memory> 
int main() { 

    while(...) { 
     std::unique_ptr<int> foobar = new int; 
    } // smart pointer foobar deletes the allocated int each iteration 

    return 0; 
} 
-2

Foobar con trỏ được tạo trên ngăn xếp, nhưng int mới được tạo trên heap. Trong trường hợp của vòng lặp while, mỗi lần mã lặp lại, foobar sẽ loại bỏ phạm vi. Int mới được tạo ra vẫn tồn tại trên heap. Trên mỗi lần lặp, một int mới được tạo ra, và con trỏ được đặt lại, có nghĩa là con trỏ không còn có thể truy cập bất kỳ (các) int trước đó trên heap.

Điều gì dường như thiếu, trong mỗi câu trả lời trước đó, và ngay cả trong câu trả lời này, là vùng heap nằm ngoài phạm vi. Có lẽ, tôi đang nhận được các thuật ngữ không chính xác, nhưng tôi biết rằng tại một số điểm heap được thiết lập lại, quá. Nó có thể xảy ra khi chương trình không còn chạy, hoặc khi máy tính bị tắt, nhưng tôi biết nó đã xảy ra.

Hãy xem câu hỏi này từ góc độ khác. Tôi đã viết bất kỳ số lượng chương trình nào, bộ nhớ bị rò rỉ. Trong tất cả các năm, tôi đã sở hữu máy tính của mình, tôi tích cực, tôi đã bị rò rỉ hơn 2 gigabyte bộ nhớ. Máy tính của tôi chỉ có 1 gig bộ nhớ. Vì vậy, nếu heap KHÔNG BAO GIỜ rơi ra khỏi phạm vi, sau đó máy tính của tôi có một số bộ nhớ kỳ diệu. Liệu một trong các bạn có quan tâm giải thích khi nào chính xác vùng heap rơi ra khỏi phạm vi?

1

Ở đây foobar là con trỏ int chiếm bộ nhớ trong ngăn xếp. Ví dụ int bạn đang tạo động với new chuyển sang vùng heap. Khi foobar vượt quá phạm vi, bạn mất tham chiếu đến nó, vì vậy bạn không thể xóa bộ nhớ được phân bổ trong heap.

Giải pháp tốt nhất sẽ là:

while(--) 
{ 
    int foobar; 
}//it goes out of scope here. deleted from stack automatically!! 

Nếu bạn vẫn muốn sử dụng việc phân bổ động sau đó làm việc này:

while(--) 
{ 
    int* foobar=new int; 
    //do your work here! 
    delete foobar; //This deletes the heap memory allocated! 
    foobar=NULL; //avoid dangling pointer! :) 
}