2012-04-10 21 views
9

Tôi mới sử dụng con trỏ thông minh trên thế giới. Tôi đã đọc xong và tất cả đều nói rằng con trỏ thông minh sẽ tránh rò rỉ bộ nhớ ngay cả khi chương trình sẽ thoát sau khi gặp phải một ngoại lệ.rò rỉ C++ trong trường hợp ngoại lệ ngay cả khi sử dụng con trỏ thông minh

Tôi đã viết xuống một chương trình đơn giản để dùng thử, nhưng Valgrind cho tôi biết chương trình của tôi đang bị rò rỉ bộ nhớ (ba allocs và chỉ một phần mềm miễn phí).

Đây là mã nguồn:

#include <iostream> 
#include <memory> 

using namespace std; 

int main() 
{ 
    auto_ptr<int> ptr_int(new int(5)); 

    throw std::bad_alloc(); 

    cout << *ptr_int; 
} 

Và báo cáo Valgrind này:

==27862== Memcheck, a memory error detector 
==27862== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al. 
==27862== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info 
==27862== Command: ./smart_pointers 
==27862== Parent PID: 5388 
==27862== 
==27862== 
==27862== HEAP SUMMARY: 
==27862==  in use at exit: 104 bytes in 2 blocks 
==27862== total heap usage: 3 allocs, 1 frees, 120 bytes allocated 
==27862== 
==27862== 4 bytes in 1 blocks are still reachable in loss record 1 of 2 
==27862== at 0x4026351: operator new(unsigned int) (vg_replace_malloc.c:255) 
==27862== by 0x804878A: main (smart_pointers.cpp:8) 
==27862== 
==27862== 100 bytes in 1 blocks are possibly lost in loss record 2 of 2 
==27862== at 0x4025BD3: malloc (vg_replace_malloc.c:236) 
==27862== by 0x40E861A: __cxa_allocate_exception (in /usr/lib/libstdc++.so.6.0.14) 
==27862== by 0x80487AE: main (smart_pointers.cpp:10) 
==27862== 
==27862== LEAK SUMMARY: 
==27862== definitely lost: 0 bytes in 0 blocks 
==27862== indirectly lost: 0 bytes in 0 blocks 
==27862==  possibly lost: 100 bytes in 1 blocks 
==27862== still reachable: 4 bytes in 1 blocks 
==27862==   suppressed: 0 bytes in 0 blocks 
==27862== 
==27862== For counts of detected and suppressed errors, rerun with: -v 
==27862== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 19 from 8) 

Không sử dụng con trỏ thông minh đảm bảo các nguồn lực được phân bổ sẽ bị phá hủy ngay cả khi một ngoại lệ xuất hiện?

+4

Bạn chưa bắt được ngoại lệ nào cả, Vì vậy, nó kết thúc lên gọi 'chấm dứt() 'mà hành vi mặc định là để gọi' hủy bỏ()'. Điều gì sẽ xảy ra nếu bạn bắt được ngoại lệ? –

+0

Nếu bạn đang sử dụng một hệ điều hành hiện đại, hệ điều hành sẽ đòi lại bất kỳ bộ nhớ nào được chương trình sử dụng khi nó thoát ra, do đó bạn không nên lo lắng về việc rò rỉ bộ nhớ.Tất nhiên, đó là một tình huống khác nếu bạn đang sử dụng tài nguyên mà bạn cần dọn dẹp một cách rõ ràng. – TheJuice

Trả lời

5

Khi std::terminate() được gọi là (như trường hợp cho một ngoại lệ còn tự do), dọn dẹp bình thường không chạy (ít nhất là trong ngăn xếp khung của main()), và như bộ nhớ như vậy bạn đã phân bổ trong stack rò rỉ khung hình, mặc dù nó được cho là được quản lý bởi một con trỏ thông minh. Khi bạn đang bắt các std::bad_alloc trong main(), và trở lại bình thường, con trỏ thông minh sẽ làm nhiệm vụ của nó.

+0

Thay đổi câu đó thành "con trỏ thông minh sẽ tránh rò rỉ bộ nhớ ngay cả trong trường hợp _handled_ execptions". Bạn không xử lý ngoại lệ. – modelnine

+0

di chuyển mã vào foo() sẽ không hữu ích nếu bạn không bắt ngoại lệ. Nếu bạn không bắt được một ngoại lệ (ở bất kỳ đâu) thì ứng dụng của bạn sẽ chấm dứt và destructors sẽ không được gọi (điều gì sẽ là điểm - hệ điều hành sẽ tự động lấy lại toàn bộ bộ nhớ trong trường hợp này). sử dụng điều này: thử { \t \t foo(); \t} catch (std :: bad_alloc ex) \t { \t} sau đó bạn sẽ thấy bộ nhớ đúng deallocated – skimon

+2

Tôi không biết về C++ 11, nhưng ban đầu, trong C++ nó đã lên đến thi cho dù destructors được gọi là một ngoại lệ unhandled. Theo điểm: Một số trình phá hủy làm nhiều hơn bộ nhớ đòi lại (ví dụ: tắt kết nối máy chủ, xóa các tệp tạm thời,…). Do đó người ta có thể lập luận rằng nó có ý nghĩa để gọi destructors ngay cả trong trường hợp này. Tuy nhiên, cho rằng nó là tầm thường để thêm một catch-tất cả để 'main' và không unwinding stack có thể giúp gỡ lỗi, nó đã không được bắt buộc. Tôi không biết liệu có bất kỳ triển khai nào thực hiện việc giải phóng ngăn xếp cho các trường hợp ngoại lệ không bị bắt. – celtschk

12

Nếu ngoại lệ không được xử lý, khi đó nó được triển khai thực hiện để xác định xem ngăn xếp sẽ bị bỏ trống trước khi gọi std::terminate.

Nếu bạn xử lý ngoại lệ, con trỏ thông minh sẽ hoạt động như mong đợi.

tham khảo:

C++ 11 15.5.1 Các std::terminate() chức năng

1 Trong một số tình huống xử lý ngoại lệ phải được bỏ hoang cho các kỹ thuật xử lý lỗi kém phần tinh tế. Những tình huống này là:

........

- khi cơ chế xử lý ngoại lệ không thể tìm thấy một handler cho một ngoại lệ ném, hoặc

........

2 Trong trường hợp này, std::terminate() được gọi. Trong trường hợp không tìm thấy trình xử lý phù hợp, nó được thực hiện xác định có hay không ngăn xếp được mở trước std::terminate() được gọi là.

+0

Tôi lấy sự tự do khi thêm Tham chiếu Chuẩn, hy vọng bạn không quan tâm đến nó. –

2

Nếu ngoại lệ không bị bắt, khi đó thư giãn được thực hiện cụ thể. Do đó trong trường hợp của bạn, nó không giải phóng bộ nhớ.

Ngoài ra, auto_ptr không còn được đề xuất nữa.

Sử dụng std :: unique_ptr:

unique_ptr<int> ptr_int(new int(5)); 
+0

Cảm ơn. Tôi biết unique_ptr. – efabor

+0

Để rời khỏi chính() sạch Tôi đã chuyển mã thành foo() Nhưng vẫn là vấn đề tương tự. Tôi nghĩ rằng nếu các ngoại lệ không được quản lý thì con trỏ thông minh sẽ không giúp được gì. Tuy nhiên tất cả các Iv đọc xong họ nói "con trỏ thông minh sẽ tránh rò rỉ bộ nhớ ngay cả trong trường hợp của execptions" #include #include using namespace std; void foo() { \t auto_ptr ptr_int (int mới (5)); \t ném tiêu chuẩn :: bad_alloc(); \t cout << * ptr_int; } int main() { \t foo(); \t cout << "END"; } – efabor

+0

Về đọc: một ngoại lệ sẽ chấm dứt quá trình của bạn và sau đó tất cả bộ nhớ sẽ được giải phóng. Bạn nên lo lắng về một ngoại lệ chưa được khai thác nhiều hơn là một sự rò rỉ tài nguyên. '#include #include sử dụng không gian tên std; int func() { \t unique_ptr ptr_int (int mới (5)); \t ném tiêu chuẩn :: bad_alloc(); \t cout << * ptr_int; \t trả về 0; } int main() { \t thử \t { \t \t func(); \t} \t bắt (...) \t { \t \t cout << "in catch all ..."<< endl; \t} \t }' Đoạn mã trên giải phóng bộ nhớ mà không gặp bất kỳ sự cố nào. – Ram

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