2013-03-05 27 views
5

Tôi có một câu hỏi ngắn. Với một hàm trả về một đối tượng của một lớp như là kết quả, tôi nên trả về những gì nếu không có kết quả (giả sử vì một chỉ mục nằm ngoài phạm vi)? Tôi có thể trả về một đối tượng "trống rỗng" nhưng làm thế nào tôi có thể chỉ ra rằng không có tính toán thành công?Làm thế nào để biết rằng không có kết quả của một hàm có giá trị trả về?

Tôi cho rằng có một cách tiếp cận chung.

+3

ném ngoại lệ http://www.cplusplus.com/doc/tutorial/exceptions/ – Tschallacka

+3

ném một ngoại lệ? – PlasmaHH

+0

@MichaelDibbets. Cảm ơn, tôi đã không sử dụng điều đó trước đây. Nếu bạn viết nó như một câu trả lời ngắn, tôi sẽ đánh dấu nó là được chấp nhận. – danijar

Trả lời

2

Bạn có thể ném ngoại lệ khi giá trị không khớp với kết quả mong đợi.

Một hướng dẫn có thể được tìm thấy tại http://www.cplusplus.com/doc/tutorial/exceptions

Một ngoại lệ làm việc với một nguyên tắc thử và nắm bắt.

Một chương trình "cố gắng" để thực thi mã. Nếu có điều gì đó bất ngờ xảy ra, mã được thực hiện "ném" một đối tượng, biến hoặc bất kỳ thứ gì và điều này sẽ bị bắt. Trong tuyên bố khai thác, bạn có thể đặt mã những gì sẽ xảy ra nếu điều bất ngờ xảy ra.

Chỉ cần làm theo hướng dẫn.

+0

Chỉ cần chỉ ra, bạn có thể tiết kiệm cho mình và mọi người khác rất nhiều đau bằng cách chỉ ném std :: exception và subclasses khi chúng cung cấp một cách duy nhất để có được một chuỗi có nghĩa là đầy đủ 'what()'. Việc ném các giá trị int int đơn giản phải là điều tồi tệ nhất có thể thực hiện được. – josefx

+0

Nhưng việc ném 0xDEAD hoặc 0xBABE thật thú vị @josefx – Tschallacka

13

Cách tiếp cận chung trong C++ là ném ngoại lệ hoặc sử dụng một số trình bao bọc như boost::optional.

Một ngoại lệ nên được ném nếu đó là lỗi nào đó, số boost::optional -approach phù hợp hơn nếu đó là trường hợp sử dụng hợp lệ của hàm của bạn để trả về kết quả trống. Một ví dụ mà nói đến cái tâm là NULL của NULL. boost::optional bật ra khá tiện dụng trong codebase của chúng tôi.

+0

Như một lưu ý phụ, trong một số video gần đây hoặc ít hơn tôi thấy * Alexandrescu * đề xuất một loại "Đặc biệt" (được gọi là như vậy?), Đó là cuối cùng 'tăng :: tùy chọn' với tùy chọn thứ hai không là một giá trị rỗng nhưng là một ngoại lệ, và do đó sẽ là khái niệm thích hợp để được sử dụng cho các trường hợp lỗi (theo constrast thành một 'tăng :: tùy chọn 'đơn giản). Nếu không có lý do âm thanh +1. –

+0

Vâng, cũng thấy điều đó và nó được gọi là 'Mong đợi '. Lý do tôi đã không đề cập đến nó là tôi vẫn xem xét nó cả * thử nghiệm và nâng cao *. Nhưng đó là một lời trêu ghẹo tốt cho người đọc nâng cao, vì vậy đây là [link] (http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling- in-C). –

3

Đi theo triết lý của phương pháp vector::at ném out_of_range ngoại lệ nếu có thể.

3

Tùy thuộc vào ngữ nghĩa của thao tác.

Nếu một lỗi xảy ra, bạn chắc chắn nên ném một ngoại lệ:

#include <stdexcept> // Necessary for standard exceptions 

X foo() 
{ 
    ... 
    if (/* something goes wrong... */) 
    { 
     // There may be a more appropriate exception class. You could 
     // also derive your own exception class from std::exception... 
     throw std::logic_error("Whatever!"); 
    } 

    ... 
} 

... 

try 
{ 
    X x = foo(); 
    // Work with x... 
} 
catch (std::logic_error const& e) // Catch what is appropriate... 
{ 
    std::cout << e.what(); 
} 

Nếu trả lại một không có giá trị không biểu thị một điều kiện lỗi, bạn có thể sử dụng Boost.Optional. Ngoài ra, với điều kiện bạn có thể tạo một đối tượng "trống rỗng" của loại X, bạn có thể nghĩ đến việc trả lại một cặp mà thành viên thứ hai là một lá cờ bool mà nói cho dù thành viên đầu tiên là một đối tượng có giá trị hay không, như sau:

std::pair<X, bool> foo(); 

... 

bool valid; 
X x; 
std::tie(x, valid) = foo(); 
if (valid) 
{ 
    // Use x... 
} 
+0

Cảm ơn bạn đã đề cập đến Boost.Optional. – danijar

+0

Cần lưu ý rằng giải pháp 'std :: pair' chỉ có ý nghĩa nếu bạn có thể tạo một giá trị rỗng của kiểu' X'. Và sau đó, đôi khi sự trống rỗng của giá trị trả về có thể được sử dụng thay cho 'bool'. – rodrigo

+0

@rodrigo: Tôi đồng ý với câu đầu tiên (sẽ chỉnh sửa, cảm ơn), trong khi tôi không muốn trả về một đối tượng trống * chỉ *: bằng cách nhìn vào chữ ký của hàm, cặp '' đã cho tôi gợi ý rằng ' X' có thể trống. Nhưng tôi đoán đó là vấn đề về hương vị. –

3

Nếu chúng ta đang nói về tình huống sai lầm, ném một ngoại lệ là giải pháp thích hợp.

#include<exception> 

Object * GenerateObject(int i) 
{ 
    if (i < 0) 
     throw std::out_of_range("i"); 

    return new Object(i); 
} 

int main(int argc, char * argv[]) 
{ 
    try 
    { 
     Object * obj = GenerateObject(-1); 

     // Succeeded 
     return 0; 
    } 
    catch (std::exception & e) 
    { 
     // Failed, exiting with error value 
     return 1; 
    } 
} 

Nếu giá trị rỗng được cho phép, bạn có thể chỉ định giá trị cụ thể cho lớp này, ví dụ:

class Rectangle 
{ 
private: 
    int left, top, width, height; 

public: 
    Rectangle(l, t, w, h) 
    { 
     left = l; 
     top = t; 
     width = w; 
     height = h; 
    } 

    public static Rectangle empty; 
} 

Rectangle Rectangle::empty = Rectangle(0, 0, -1, -1); 

// ... 

Rectangle DoSth(int i) 
{ 
    // i < 0 is NOT considered an error here 
    if (i < 0) 
      return Rectangle::empty; 

    // Further processing 
} 
+1

Tại sao không ngoại lệ ['std :: out_of_range'] (http://en.cppreference.com/w/cpp/error/out_of_range)? – BoBTFish

+0

Ở đây tốt hơn, tôi không có kiến ​​thức sâu rộng về ngoại lệ của STL. Tôi sẽ sửa lại. – Spook

+0

Cảm ơn mã ví dụ. – danijar

0

Bạn có thể ghép một kiểu liệt kê với kiểu đối tượng đang được trả về. Nếu liệt kê trả về là một giá trị nhất định, đối tượng là hợp lệ, nếu không đối tượng ở trạng thái không hợp lệ.

// This is a working C++11 example. 
#include <utility> 
#include <memory> 

enum result 
{ 
    ok, 
    out_of_range, 
    some_other_error 
}; 

class object 
{ 
    public: 
     object() {} 
}; 

typedef std::shared_ptr<object> object_ptr; 

typedef std::pair< result, object_ptr > return_type; 

return_type some_function(int index) 
{ 
    if (index > 5) 
    { 
     return return_type{ result::out_of_range, nullptr }; 
    } 

    return return_type{ result::ok, object_ptr{ new object() } }; 
} 

int main() 
{ 
    return_type res = some_function(10); 
    if (res.first == result::ok) 
    { 
     // Do something with res.second 
    } 
    else 
    { 
     // Handle the error 
    } 
} 

Tôi có thể chỉ cần ném ngoại lệ thay thế.

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