简体   繁体   中英

Function Return Type: Pointer, Reference or something else?

Let us assume I always need the direkt return type of the function to be of a errorcode (success of calculation or failure) , then I will return some arguments as parameters. Is it better to define them as reference (and create them before empty) or better to return pointer?

Edit: I should be more precise: The errorcode is obligatory because I have to stick to the coding guidline given.

Possibility A:

ErrorCode func( some_parameters ... , ReturnType & result)
...
ReturnType result; // empty constructor, probably not good practice
func( some_parameters ..., result)

Possibility B:

ErrorCode func( some_parameters ... , ReturnType * result){
    ...
    result =  new ReturnType(...)
    ...
}
...
ReturnType * result; // void pointer
func( some_parameters ..., result)
...
delete result; // this is needed if I do not use a smart pointer

Even better: Maybe you have a more appropriate solution?

Edit: Please indicate which standard you are using, since unfortunatelly (guidelines) I have to stick to C++98.

I would do the following (and in general do)

1.) throw an exception instead of returning error codes

if this is not possible (for any reason)

2.) return the pointer directly (either raw or std::unique_ptr) and return nullptr for failure

if return type has to be bool or not all objects returned are (pointers / heap allocated)

3.) return your error code (bool or enum class) and accept a reference parameter for all objects that are to be initialized (must have objects so to speak) and pointers to objects that may be optionally created / initialized

if the object cannot be created in advance to the call (eg because it is not default constructible)

4.) pass a reference to a pointer (raw or std::unique_ptr) or a pointer to a pointer, which will then be filled by the function

std::optional (or similar) may be an option if you only have a true/false return code.

I don't like returning std::pair or std::tuple because it can make your code look quite annoying if you have to start using .first/.second or std::get<>() to access your different return types. Using std::tie() can reduce this a little bit, but it is not (yet) very comfortable to use and prevents the use of const.

Examples:

std::unique_ptr<MyClass> func1() { /* ... */ throw MyException("..."); }

std::unique_ptr<MyClass> func2() { /* ... */ }

ErrorCode func3(MyClass& obj, std::string* info = nullptr) { /* ... */ }

ErrorCode func4(std::unique_ptr<MyClass>& obj) { /* ... */ }

int main()
{
     try 
     {
          auto myObj1 = func1();
          // use ...
     }
     catch(const MyException& e)
     {
          // handle error ...
     }

     if(auto myObj2 = func2())
     {
          // use ...
     }

     MyClass myObj3;
     std::string info;
     ErrorCode error = func3(myObj3, &info);
     if(error == ErrorCode::NoError)
     {
          // use ...
     }

     std::unique_ptr<MyClass> myObj4;
     ErrorCode error = func4(myObj4);
     if(error == ErrorCode::NoError)
     {
          // use ...
     }
 }

Edit: And in general it is advisable to keep your API consistent, so if you already have a medium or large codebase, which makes use of one or the other strategy you should stick to that (if you do not have good reasons not to).

This is a typical example for std::optional . Sadly it isn't available yet, so you want to use boost::optional .

This is assuming that the result is always either "success with result" or "fail without result". If your result code is more complicated you can return
std::pair<ResultCode, std::optional<ReturnType>> .

It would be good style to to use the return value for all return information. For example:

std::tuple<bool, ReturnType> func(input_args....)

Alternatively, the return type could be std::optional (or its precursor) if the status code is boolean, with an empty optional indicating that the function failed.

However, if the calculation is supposed to normally succeed, and only fail in rare circumstances, it would be better style to just return ReturnType , and throw an exception to indicate failure.

Code is much easier to read when it doesn't have error-checking on every single return value; but to be robust code those errors do need to be checked somewhere or other. Exceptions let you handle a range of exceptional conditions in a single place.

不知道它是否适用于你的情况,但如果你只有两个状态返回类型,那么可能只是从你的函数返回指针然后测试它是否为nullptr?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM