简体   繁体   中英

What should the return type be when the function might not have a value to return?

In the old days, you might have a function like this:

const char* find_response(const char* const id) const;

If the item could not be found, then a null could be returned to indicate the fact, otherwise obviously return the relevant string.

But when the function is changed to:

const std::string& find_response(const std::string& id) const;

What do you return to indicate item not found?

Or should signature really be:

bool find_response(const std::string& id, std::string& value) const;

What would be the most elegant modern C++ way?

boost::optional . It was specifically designed for this kind of situation.

Note, it will be included in upcoming C++14 standard as std::optional . Update: After reviewing national body comments to N3690, std::optional was voted out from C++14 working paper into a separate Technical Specification. It is not a part of the draft C++14 as of n3797.

Compared to std::unique_ptr , it avoids dynamic memory allocation, and expresses more clearly its purpose. std::unique_ptr is better for polymorphism (eg factory methods) and storing values in containers, however.

Usage example:

#include <string>
#include <boost/none.hpp>
#include <boost/optional.hpp>

class A
{
private:
    std::string value;
public:
    A(std::string s) : value(s) {}

    boost::optional<std::string> find_response(const std::string& id) const
    {
        if(id == value)
            return std::string("Found it!");
        else
            return boost::none;
        //or
        //return boost::make_optional(id == value, std::string("Found it!"));
    }

    //You can use boost::optional with references,
    //but I'm unfamiliar with possible applications of this.
    boost::optional<const std::string&> get_id() const
    {
        return value;
    }
};

#include <iostream>

int main()
{
    A a("42");
    boost::optional<std::string> response = a.find_response("42"); //auto is handy
    if(response)
    {
        std::cout << *response;
    }
}

What would be the most elegant modern C++ way?

There's, as always, not just one solution to this problem.

If you decide to go for any solution that references the original resonse instance, you're on a slippery road when it comes to aliasing and memory management, especially in a multi threaded environment. By copying the response to the caller, no such issues arises.

Today, I would do this:

std::unique_ptr<std::string> find_response(const std::string& id) const;

That way, you can check for nullptr as "in the olden days" and it's 100% clear who's responsibility it is to clear up the returned instance: the caller.

The only downside I see of this, is the additional copy of the response string, but don't dismiss that as a downside until measured and proven so.

Another way is to do as is done when searching std::set<> and std::map<> - return a std::pair<bool, const char*> where one value is bool is_found and the other is const char* response . That way you don't get the "overhead" of the additional response copy, only of the returned std::pair<> which is likely to be maximally optimized by the compiler.

如果函数通过引用返回一个字符串,但需要能够指示不存在这样的字符串,那么最明显的解决方案是返回一个指针,该指针基本上是一个可以为null的引用,即确切地追求的内容。

const std::string* find_response(const std::string& id) const;

There are several good solutions here already. But for the sake of completeness I'd like to add this one. If you don't want to rely on boost::optional you may easily implement your own class like

class SearchResult
{
    SearchResult(std::string stringFound, bool isValid = true)
        : m_stringFound(stringFound),
        m_isResultValid(isValid)
    { }

    const std::string &getString() const { return m_stringFound; }
    bool isValid() const { return m_isResultValid; }

private:
    std::string m_stringFound;
    bool m_isResultValid;
};

Obviously your method signature looks like this then

const SearchResult& find_response(const std::string& id) const;

But basically that's the same as the boost solution.

Use of pointers in C++ is forgiven if you need to return a nullable entity. This is widely accepted. But of course bool find_response(const std::string& id, std::string& value) const; is quite verbose. So it is a matter of your choice.

I think the second way is better. Or you can write like this:

int find_response(const std::string& id, std::string& value) const;

if this function return -1, it tells that you don't find the response.

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