17

在过去,您可能有这样的功能:

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

如果找不到该项目,则可以返回 null 以指示该事实,否则显然返回相关字符串。

但是当函数改为:

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

您返回什么以表明未找到项目?

或者签名真的应该是:

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

什么是最优雅的现代 C++ 方式?

4

6 回答 6

22

boost::optional. 它是专门为这种情况设计的。

请注意,它将作为std::optional. 更新:在审查了国家机构对 N3690 的评论后,std::optional从 C++14 工作文件中被否决为单独的技术规范。从 n3797 开始,它不是 C++14 草案的一部分。

相比std::unique_ptr,它避免了动态内存分配,并且更清楚地表达了它的目的。std::unique_ptr然而,对于多态性(例如工厂方法)和将值存储在容器中更好。

使用示例:

#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;
    }
}
于 2013-06-12T09:32:21.233 回答
5

什么是最优雅的现代 C++ 方式?

与往常一样,解决这个问题的方法不止一种。

如果您决定采用任何引用原始 resonse 实例的解决方案,那么在别名和内存管理方面,尤其是在多线程环境中,您将走上一条滑坡。通过将响应复制给调用者,不会出现此类问题。

今天,我会这样做:

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

这样,您可以检查为nullptr“在过去的日子” ,并且100% 清楚谁负责清理返回的实例:调用者。

我看到的唯一缺点是响应字符串的附加副本,但在测量和证明之前不要将其视为缺点。

std::set<>另一种方法是按照搜索时所做的那样做std::map<>- 返回std::pair<bool, const char*>一个值在哪里,另一个在bool is_found哪里const char* response。这样你就不会得到额外响应副本的“开销”,只有返回的响应副本std::pair<>可能会被编译器最大限度地优化。

于 2013-06-12T09:30:19.433 回答
3

如果函数通过引用返回一个字符串,但需要能够指示不存在这样的字符串,最明显的解决方案是返回一个指针,它基本上是一个可以为空的引用,即正是所寻求的。

const std::string* find_response(const std::string& id) const;
于 2013-06-12T14:56:21.777 回答
1

这里已经有几个很好的解决方案。但为了完整起见,我想添加这个。如果您不想依赖,boost::optional可以轻松实现自己的类,例如

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;
};

显然你的方法签名看起来像这样

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

但基本上这与boost解决方案相同。

于 2013-06-13T07:13:19.403 回答
0

如果您需要返回一个可为空的实体,则可以在 C++ 中使用指针。这被广泛接受。但当然bool find_response(const std::string& id, std::string& value) const;是相当冗长。所以这是你选择的问题。

于 2013-06-12T09:30:29.113 回答
-2

我认为第二种方式更好。或者你可以这样写:

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

如果这个函数返回 -1,它告诉你没有找到响应。

于 2013-06-12T09:44:45.967 回答