Подтвердить что ты не робот

Каким должен быть тип возврата, когда функция может не иметь значения для возврата?

В старые времена у вас может быть такая функция:

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

Если элемент не может быть найден, то для указания факта может быть возвращен нуль, иначе, очевидно, вернуть соответствующую строку.

Но когда функция изменена на:

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

Что вы возвращаете, чтобы указать, что элемент не найден?

Или должна быть подпись действительно:

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

Какой будет самый элегантный современный С++-способ?

4b9b3361

Ответ 1

Какой будет самый элегантный современный С++-способ?

Как всегда, это не просто решение этой проблемы.

Если вы решите пойти на любое решение, которое ссылается на исходный экземпляр ответа, вы находитесь на скользкой дороге, когда дело доходит до сглаживания и управления памятью, особенно в многопоточной среде. При копировании ответа на вызывающего абонента такие проблемы не возникают.

Сегодня я бы сделал это:

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

Таким образом, вы можете проверить nullptr как "в прежние дни" и, на 100% понять, кто несет ответственность за очистку возвращаемого экземпляра: вызывающего.

Единственный недостаток, который я вижу в этом, - это дополнительная копия строки ответа, но не отклоняйте ее как недостаток, пока не будете измерены и не доказаны.

Другой способ - сделать так, как это делается при поиске std::set<> и std::map<> - вернуть a std::pair<bool, const char*>, где одно значение bool is_found, а другое - const char* response. Таким образом, вы не получите "служебных" дополнительных копий ответа, а только возвращаемого std::pair<>, который может быть максимально оптимизирован компилятором.

Ответ 2

boost::optional. Он был специально разработан для такого рода ситуаций.

Обратите внимание, что он будет включен в следующий стандарт С++ 14 как std::optional. Обновление: после просмотра комментариев национального органа N3690, std::optional был отклонен от С++ 14 бумагу в отдельную техническую спецификацию. Он не является частью проекта С++ 14 по состоянию на n3797.

По сравнению с std::unique_ptr он избегает распределения динамической памяти и более четко выражает ее назначение. std::unique_ptr лучше для полиморфизма (например, методы factory) и хранения значений в контейнерах.

Пример использования:

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

Ответ 3

Если функция возвращает строку по ссылке, но ей нужна возможность указать, что такой строки нет, наиболее очевидным решением является возврат указателя, который в основном является ссылкой, которая может быть нулевой, т.е. именно то, что было запрошено после того, как.

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

Ответ 4

Здесь уже есть несколько хороших решений. Но ради полноты я хотел бы добавить это. Если вы не хотите полагаться на 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;

Но в основном это то же самое, что и решение для ускорения.

Ответ 5

Использование указателей в С++ прощено, если вам нужно вернуть объект с возможностью NULL. Это широко принято. Но, конечно, bool find_response(const std::string& id, std::string& value) const; довольно многословно. Так что это вопрос вашего выбора.

Ответ 6

Я думаю, что второй способ лучше. Или вы можете написать вот так:

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

если эта функция возвращает -1, она сообщает, что вы не находите ответ.