2009-08-20 3 views
10

Vì vậy, tôi sử dụng Qt rất nhiều với sự phát triển của mình và yêu thích nó. Mẫu thiết kế thông thường với các đối tượng Qt là phân bổ chúng bằng cách sử dụng new.Chính sách bắt std :: bad_alloc

Khá nhiều ví dụ (đặc biệt là mã được tạo bởi nhà thiết kế Qt) hoàn toàn không kiểm tra ngoại lệ std::bad_alloc. Kể từ khi các đối tượng được phân bổ (thường là vật dụng và như vậy) là nhỏ, điều này hầu như không bao giờ là một vấn đề. Sau khi tất cả, nếu bạn không phân bổ một cái gì đó như 20 byte, tỷ lệ cược là không có nhiều bạn có thể làm để khắc phục vấn đề.

Hiện tại, tôi đã áp dụng chính sách bao gồm phân bổ "lớn" (bất kỳ thứ gì trên một hoặc hai trang) trong thử/nắm bắt. Nếu điều đó không thành công, tôi hiển thị một thông báo cho người dùng, khá nhiều thứ nhỏ hơn, tôi sẽ chỉ cho phép ứng dụng gặp sự cố với một ngoại lệ std::bad_alloc.

Vì vậy, tôi tự hỏi các trường học nghĩ về điều này là gì về điều này?

Có chính sách tốt để kiểm tra từng hoạt động của new không? Hay chỉ những người tôi mong đợi có khả năng thất bại?

Ngoài ra, đây rõ ràng là một câu chuyện hoàn toàn khác khi giao dịch với môi trường nhúng nơi tài nguyên có thể bị hạn chế hơn nhiều. Tôi yêu cầu trong bối cảnh của một ứng dụng máy tính để bàn, nhưng sẽ quan tâm đến các câu trả lời liên quan đến các kịch bản khác.

Trả lời

17

Vấn đề không phải là "nơi để bắt" nhưng "phải làm gì khi một ngoại lệ bị bắt".

Nếu bạn muốn kiểm tra, thay vì gói với try catch bạn nên sử dụng

#include <new> 
    x = new (std::nothrow) X(); 
    if (x == NULL) { 
     // allocation failed 
    } 

thực hành thông thường của tôi là

  • trong chương trình không tương tác, đánh bắt ở cấp chính là một nhà trưng bày thông báo lỗi đầy đủ ở đó.

  • trong chương trình có vòng lặp tương tác người dùng, tôi cũng bắt được vòng lặp để người dùng có thể đóng một số thứ và cố gắng tiếp tục.

Ngoại lệ, có những nơi khác bắt giữ có ý nghĩa nhưng hiếm.

+1

thực sự không có gì mới là một lựa chọn khả thi, nhưng nếu có một vài phân bổ trong một khối mã nhất định, nó sẽ có nhiều chi tiết hơn là chỉ sử dụng khối try/catch. Tôi đồng ý 100% rằng "phải làm gì" là câu hỏi thực sự, vì trong các tình huống bộ nhớ thực sự giới hạn số tiền bạn có thể làm để sửa chữa mọi thứ. –

+1

Không quá nhiều "phải làm gì", nhưng "bạn có thể làm bất cứ điều gì cả" – jalf

+0

Nếu bạn bắt đủ cao, một số bộ nhớ có thể đã được giải phóng trong khi thư giãn. Bạn có thể chắc chắn rằng một cái gì đó được giải thoát, sử dụng new_handler hoặc các thủ thuật như 'int flag = false; thử {vector v (1000); flag = true; doEventLoop(); } catch (bad_alloc) {if (flag) cout << "Tôi có 4k để sử dụng để nhắc người dùng \ n"; } ' –

6

Tôi thường bắt ngoại lệ tại thời điểm người dùng đã bắt đầu một hành động. Đối với ứng dụng giao diện điều khiển, điều này có nghĩa là trong main, đối với các ứng dụng GUI tôi đặt trình xử lý ở những nơi như trình xử lý nút bấm trên màn hình và như vậy.

Tôi tin rằng nó có ý nghĩa ít khi bắt ngoại lệ ở giữa hành động, người dùng thường mong đợi hoạt động thành công hoặc hoàn toàn thất bại.

9

Xử lý ngoại lệ khi bạn có thể. Nếu phân bổ không thành công và ứng dụng của bạn không thể tiếp tục mà không có bộ nhớ đó, tại sao lại phải kiểm tra lỗi?

Xử lý lỗi khi số có thể được xử lý, khi có cách khôi phục có ý nghĩa. Nếu không có gì bạn có thể làm về lỗi, chỉ cần để nó lan truyền.

+0

Tôi muốn chấp nhận cả bạn và người lập trình, cả hai dường như là câu trả lời hay. Vì AProgrammer là lần đầu tiên, tôi chấp nhận của anh ấy. –

+0

yup yup. Anh ấy cũng chi tiết hơn – jalf

0

Xử lý nó trong main() (hoặc xử lý đầu mức ngoại lệ tương đương trong Qt)

Lý do là std :: bad_alloc hoặc xảy ra khi bạn cạn kiệt không gian bộ nhớ (2 hoặc 3 GB trên 32 hệ thống bit, doesn 't xảy ra trên hệ thống 64 bit) hoặc khi bạn xả không gian hoán đổi. Phân bổ heap hiện đại không được điều chỉnh để chạy từ không gian hoán đổi, do đó sẽ là một cái chết chậm, ồn ào - rất có thể người dùng của bạn sẽ giết ứng dụng của bạn trước khi giao diện người dùng không còn đáp ứng. Và trên Linux, việc xử lý bộ nhớ hệ điều hành là rất nghèo theo mặc định rằng ứng dụng của bạn có khả năng bị giết tự động.

Vì vậy, có rất ít bạn có thể làm. Thú nhận bạn có lỗi và xem liệu bạn có thể lưu bất kỳ tác phẩm nào mà người dùng có thể đã thực hiện hay không. Để có thể làm như vậy, tốt nhất là nên hủy bỏ càng nhiều càng tốt. Có, điều này thực tế có thể mất một số đầu vào người dùng cuối cùng. Nhưng đó là hành động rất có khả năng kích hoạt tình hình OOM .. Mục đích là để lưu bất cứ dữ liệu nào bạn có thể tin tưởng.

3

Đây là một chủ đề tương đối cũ, nhưng nó đã đưa ra khi tôi đang tìm kiếm "std :: bad_alloc" cân nhắc khi thực hiện mới/xóa trọng ở đây vào năm 2012.

tôi sẽ không mất khái niệm "oh cũng không có gì bạn có thể làm dù sao "như là một lựa chọn khả thi. Cá nhân tôi sử dụng trong phân bổ của riêng tôi "if (alloc()) {} else {error/handling}" cách được đề cập ở trên. Bằng cách này tôi có thể xử lý và/hoặc báo cáo từng trường hợp theo ngữ cảnh có ý nghĩa của riêng họ.

Bây giờ, một số giải pháp khả thi khác là: 1) Ghi đè lên/xóa mới cho ứng dụng mà bạn có thể thêm của riêng bạn ra khỏi xử lý bộ nhớ.

Mặc dù giống như các áp phích khác, và đặc biệt là với kiến ​​thức về các ngữ cảnh cụ thể, tùy chọn chính có thể là chỉ tắt ứng dụng. Nếu đây là trường hợp bạn sẽ muốn người xử lý của bạn hoặc là có preallocated nó cần thiết bộ nhớ, và, hoặc, sử dụng bộ nhớ tĩnh để hy vọng rằng xử lý nó tự sẽ không trở nên kiệt sức.

Ở đây bạn có thể có ít nhất có lẽ một hộp thoại bật lên và nói điều gì đó trên các dòng: "Ứng dụng hết bộ nhớ. Đây là lỗi nghiêm trọng và phải tự chấm dứt. Ứng dụng phải được chạy trong yêu cầu bộ nhớ hệ thống tối thiểu. Gửi báo cáo gỡ lỗi đến xxxx ". Trình xử lý cũng có thể lưu bất kỳ công việc nào đang tiến hành, v.v., phù hợp với ứng dụng.

Ở bất kỳ mức nào bạn sẽ không muốn sử dụng điều này cho một cái gì đó quan trọng như (cảnh báo, hài hước nghiệp dư phía trước): tàu con thoi, màn hình nhịp tim, máy thẩm tách thận, v.v ... các giải pháp tất nhiên, sử dụng két an toàn, phương pháp thu gom rác khẩn cấp, 100% thử nghiệm/gỡ lỗi/mờ, v.v.

2) Tương tự như đầu tiên, đặt set_new_handler() toàn cầu hết điều kiện bộ nhớ ở phạm vi toàn cầu. Ít nhất có thể xử lý mọi thứ như đề cập trong # 1.

1

Câu hỏi thực sự là reallty nên bạn bắt std :: bad_alloc ngoại lệ? Tôi hầu hết các trường hợp nếu bạn hết bộ nhớ, bạn vẫn phải chịu số phận và có thể xem xét kết thúc chương trình của mình.