2011-01-31 29 views
7

tôi muốn lấy được từ std :: exception để thêm thông tin cụ thể vào tệp nhật ký của tôi, nhưng tôi không thể tìm cách truy cập .what() từ std :: exception.xuất phát từ std :: ngoại lệ

hơn nữa, tôi biết rằng không an toàn để tạo chuỗi trong trình xử lý ngoại lệ của tôi, nhưng tôi không phải là chuyên gia về chủ đề này, vì vậy, một số giải pháp thay thế an toàn hơn là gì?

struct Exception : public std::exception, private boost::noncopyable 
{ 
    public: 
     Exception(std::string msg) 
      : message(msg) 
     {} 
     ~Exception() 
     {} 

     virtual const char* what() const throw 
     { 
      std::string what = message + // and now what? base.what() 
      LOG(what); // write to log file 
      return what.c_str(); 
     } 

    private: 
     std::string message; 
}; 

EDIT: tôi thực sự đã đặt câu hỏi của mình theo cách sai. Tôi khá hứng thú với sự an toàn, tôi chỉ nghĩ rằng sẽ tốt hơn nếu có nhiều dữ liệu hơn để đăng nhập. tôi đã sai.

bây giờ, tôi không quá hoang tưởng về bad_alloc bị ném bởi chuỗi thư trong trường hợp có một bad_alloc trước đây, tôi muốn có một thông điệp gọn gàng. được nói rằng tôi đã viết lại một số nội dung:

struct Exception : public std::exception 
{ 
    public: 
     Exception(std::string msg) 
      : message(msg) 
     {} 
     ~Exception() 
     {} 

     virtual const char* what() const throw 
     { 
      LOG(what); // write to log file 
      return what.c_str(); 
     } 

    private: 
     std::string message; 
}; 

hiện vẫn còn bất kỳ mối lo ngại lớn nào về mã đó không? các LOG() ném std :: trường hợp ngoại lệ tôi một cái gì đó đi sai, bởi vì tôi không muốn một vòng lặp vô hạn của đăng nhập gọi bằng lớp ngoại lệ có nguồn gốc, và lớp đó một lần nữa gọi đăng nhập mà sẽ gây ra cùng một exeception một lần nữa. Thao tác này có giống như tôi muốn, hoặc sẽ là ngoại lệ ghi nhật ký trong cuộc gọi lớp kết thúc của tôi() hoặc gây ra kết xuất lõi?

+2

Re: Các giải pháp thay thế an toàn hơn. Đây là một câu hỏi lớn. Thích hợp cho câu hỏi riêng của nó. –

+1

Chào mừng bạn đến với Stack Overflow. Có vẻ như bạn đang hỏi * hai * câu hỏi (có nghĩa là bạn nên tạo hai bài đăng riêng biệt). Một yêu cầu làm thế nào để gọi phương thức kế thừa từ lớp cơ sở và phương thức kia yêu cầu cách lưu trữ một thông báo ngoại lệ mà không có chuỗi (có lẽ vì bạn không muốn cấp phát bộ nhớ và phải chịu rủi ro 'bad_alloc'). Không thực sự có bất cứ điều gì liên quan đến việc phát sinh từ 'std :: exception' nói riêng. Các câu hỏi riêng biệt, cụ thể dẫn đến nhiều tiêu đề câu hỏi mô tả hơn và câu trả lời hữu ích hơn. Vui lòng xem xét tách câu hỏi này. –

+2

Nếu mã của bạn ném ngoại lệ loại Ngoại lệ ("..."), bạn mong đợi điều gì std :: exception :: what() trả về? Tôi không nghĩ rằng nó sẽ chứa bất cứ điều gì hữu ích (nếu nó có chứa bất cứ điều gì cả). Tôi sẽ đề nghị chỉ cần trả lại message.c_str(). – Ferruccio

Trả lời

9

EDIT: Kể từ khi viết câu trả lời này, tôi đã vấp khi Error and Exception Handling phần trong tài liệu Boost. Tôi muốn giới thiệu tài liệu đó qua câu trả lời này.


Trước hết, làm cho ngoại lệ của bạn không thể sao chép là một ý tưởng tồi. Khi bạn viết một cái gì đó chẳng hạn như

// could be any exception, doesn't matter. 
throw Exception(...); 

Thời gian chạy tạo bản sao của đối tượng đó vào một vị trí đặc biệt. Một số trình biên dịch có thể tối ưu hóa điều này và tạo đối tượng gốc ở vị trí đó, nhưng The C++ Programming Language nói đó là bản sao và tôi cũng tin đó là tiêu chuẩn nói, mặc dù tôi không chắc chắn. Bạn có thể thoát khỏi điều này trong môi trường hiện tại của bạn, nhưng điều đó có thể không phải lúc nào cũng đúng.

Sau đó, mọi thứ khác tùy thuộc vào cách bạn hoang tưởng với các trường hợp góc.

Phần cấp phát bộ nhớ hầu như không ổn định trong mệnh đề ngoại lệ (tức là hàm tạo). Nếu phân bổ bộ nhớ điều này xảy ra thất bại (tức std::bad_alloc được ném), có hai khả năng, tùy thuộc vào cách bạn viết throw tuyên bố của bạn:

  1. std::string được tạo ra trước khi tuyên bố throw, std::bad_alloc thay thế ngoại trừ bạn nghĩ rằng bạn sẽ nâng cao, vấn đề là loại báo cáo xấu.
  2. std::string được tạo nội tuyến trong lệnh gọi hàm tạo. Nếu điều này được coi là "trong quá trình xử lý ngoại lệ" theo tiêu chuẩn, thì std::unexpected()/std::terminate() sẽ được gọi và về cơ bản bạn có được một kết xuất lõi.

Trong mọi trường hợp, có vẻ như bạn sẽ không nhận được hiệu quả mong muốn báo cáo lỗi của bạn.

Tôi luôn khuyên bạn nên tạo một loại trạng thái tạm thời không phân bổ bộ nhớ trong hàm tạo và đợi cuộc gọi đến std::what() để tạo chuỗi báo cáo lỗi, nhưng điều đó vẫn có thể dẫn đến trường hợp # 1. Bạn có thể sử dụng một số kích thước bộ đệm xác định thời gian biên dịch để đảm bảo rằng không xảy ra.

Nhiều người sẽ nói với bạn rằng họ chưa bao giờ gặp vấn đề với việc phân bổ chuỗi trong các nhà xây dựng vì không thể std::bad_alloc trừ khi ngoại lệ ban đầu là std::bad_alloc ngay từ đầu. Do đó, nó phụ thuộc vào mức độ hoang tưởng của bạn.

+0

Lưu ý: Tôi không có sẵn sách để tham chiếu chính xác ... –

4

Tôi sẽ không đi vào vô số vấn đề có với mã của bạn bởi vì nó là một rất lớn có thể của sâu. Nhưng đây là cách bạn gọi một phương pháp lớp cơ sở:

std::exception::what() 
+0

BTW, tôi đã đổi tên biến cục bộ của bạn. –

+1

Giá trị trả lại không khớp với loại trả về? – UncleBens

+0

@Uncle: Cảm ơn bạn đã chỉ ra sự lười biếng của tôi. :) Đã sửa. –

-1

cho phần thứ hai. Tôi có vài trăm kloc chạy trên> 100 nền tảng có lớp std :: exception bắt nguồn với std :: string members. Không bao giờ có bất kỳ vấn đề với nó

class myex: public std::exception 
{ 
public: 
    std::string m_msg; 
    std::string m_className; 
    int m_rc; 
... 
3

Câu trả lời cho câu hỏi này là, trừ khi bạn đã đặt giá trị là what() sẽ trở về từ std :: exception thì bạn không muốn gọi nó. Thực tế của vấn đề là nó sẽ hành xử theo những cách bạn có thể không mong đợi và không giống nhau trên các triển khai khác nhau.

Lưu ý rằng tiêu chuẩn không cung cấp chức năng nào trong std :: exception để cung cấp giá trị chuỗi để bắt đầu. Những triển khai thực sự cung cấp thông tin hữu ích từ việc gọi std :: exception :: what() thêm chức năng bổ sung, không chuẩn vào lớp. Ví dụ: MSVC có một hàm tạo exception(char const* const&). Đây không phải là tiêu chuẩn và có thể bạn không muốn phụ thuộc vào nó.

Đặt cược của bạn tốt hơn là không bao giờ gọi std :: exception :: những gì từ một lớp dẫn xuất. Chắc chắn, làm upcalls trong các phiên bản tùy chỉnh của bạn mà subclass những điều THEO std :: ngoại lệ, nhưng không làm điều đó trong các dẫn xuất trực tiếp.

Nếu bạn nhấn mạnh vào việc gọi hàm này trực tiếp thì bạn nên kiểm tra tốt hơn cho NULL vì đó là những gì bạn có thể sẽ nhận được.

+0

+1 để có câu trả lời hay, nhưng bạn không trả lời câu hỏi thực tế của mình, không liên quan gì đến ngoại lệ. Làm thế nào để gọi một phương thức lớp cơ sở? –

+0

Nếu bạn nói như vậy, John. –

+0

cảm ơn noah, @ john, tôi đoán tôi thực sự hỏi câu hỏi sai cách xung quanh. Tôi là rahter interessted trong an toàn, tôi chỉ nghĩ rằng tôi có thể có nhiều dữ liệu hơn cho việc đăng nhập từ lớp cơ sở. có vẻ như tôi đã hoàn toàn sai – cppanda

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