Это хороший дизайн для возврата значения по параметру? - PullRequest
22 голосов
/ 16 марта 2010
bool is_something_ok(int param,SomeStruct* p)
{
    bool is_ok = false;

    // check if is_ok

    if(is_ok)
       // set p to some valid value
    else
       // set p to NULL
    return is_ok;
}

эта функция возвращает true и устанавливает p в допустимое значение, если "что-то в порядке" в противном случае верните false и установите p в NULL

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

Кстати: есть ли какая-нибудь авторитетная книга / статья о дизайне API?

Ответы [ 9 ]

13 голосов
/ 16 марта 2010

Поскольку вы пометили вопрос как C ++, а не как C, я бы предложил вам:

  • возвращает значение напрямую
  • если у вас более одного значения, используйте выходные параметры
  • по возможности используйте неконстантные ссылки в качестве выходного параметра (вместо указателей) и используйте const-ссылки для входных параметров.
  • если что-то пошло не так, выведите исключение вместо возврата false или -1.

Но это только некоторые общие намеки. Лучший путь всегда зависит от конкретной проблемы ...

3 голосов
/ 16 марта 2010

Зависит от того, как вы хотите обрабатывать «ошибки».

Например, возьмите стандартную функцию atoi. Он преобразует строку в целое число, но если строка не содержит числа, что она должна вернуть? В этом случае среда выполнения C / C ++ установит глобальную переменную errno. Альтернативой было бы сгенерировать исключение.

Лично мне не очень нравятся обе эти альтернативы. Поэтому, если я вообще использую следующие правила:

  • Существует ли значение в диапазоне возможных возвращаемых значений, которое можно использовать для указания ошибки, и у меня есть только 1 возможный тип ошибки? В этих случаях я использую возвращаемое значение, чтобы указать на ошибку. Например. такая функция, как FindEmployee, может просто вернуть NULL, если сотрудник не найден.
  • Если все возможные значения могут быть возвращены функцией (как в примере atoi), используйте выходной аргумент для возвращаемого значения и позвольте функции вернуть логическое значение. Если у вас более 1 возможного случая ошибки, верните перечисление, которое указывает на тип ошибки (или успеха), который произошел.
2 голосов
/ 17 февраля 2012

По поводу вашего вопроса по книге об API дизайне. Ищите «Дизайн API для C ++» Мартина Редди, который был опубликован в 2011 году.

В качестве комментария к принятому ответу. В книге автор фактически предлагает предпочесть константные ссылки для входных параметров и указатели для выходных параметров, поскольку это указывает клиенту более явно, что параметр можно изменить, например foo (bar) против foo (& bar).

Также вы можете посмотреть доклад Как разработать хороший API и почему это важно . Который использует в основном Java, однако, как я помню.

2 голосов
/ 16 марта 2010

Я бы сказал, это зависит. Насколько дорог ваш тип для копирования конструкции? Можете ли вы написать свою функцию RVO -Friendly? По крайней мере, до тех пор, пока у нас не появится C ++ 0x с rvalue ссылками , я бы рекомендовал не возвращать «дорогие» типы (такие как std::vector<std::string>), а скорее передавать их как ссылки, например, Применение:

void split(const std::string &txt, char sep, std::vector<std::string> &out);

вместо:

std::vector<std::string> split(const std::string &txt, char sep);

В зависимости от того, как вы пишете свою функцию, возможно, что RVO включится, но, по моему опыту, это не то, на что вы обычно можете положиться.

2 голосов
/ 16 марта 2010

Я склонен делать это. Альтернатива в вашем примере - либо кодировать две вещи в одно возвращаемое значение (например, используя NULL в качестве специального значения), либо возвращать структуру.

Кодирование двух вещей иногда может быть невозможно, и это немного подвержено ошибкам. Возвращение структуры - это много дополнительной работы и беспорядка. Поэтому я склонен делать то, что ты сделал. Я склонен полагать, что «необработанные» указатели и ссылки в списке параметров предназначены для возврата значений в, и они будут «константными», если они будут только для передачи данных.

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

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

1 голос
/ 20 марта 2010

Я бы предложил возвратить Result-Type напрямую, вот так:

SomeStruct doSomething(int param) {...}

и выдает исключение в случаях, когда функция не может обработать (tux21b уже упоминал об этом). В качестве альтернативы вы можете вернуть два типа с помощью std::pair, не выдавая исключение, например, так:

pair<SomeStruct, bool> doSomething(int param) {...}

И в-третьих, мне нравится объявлять выходные параметры в виде указателей вместо ссылок (как вы упомянули), потому что в коде вызова я вижу разницу входных и выходных параметров. С учетом функции:

void doSomething(const Somestruct& in, Somestruct* out) {...}

Тогда в коде вызова видно (не глядя на объявление функции), что является входным параметром и каков выходной параметр (если я последовательно применяю эту концепцию).

SomeStruct a;
SomeStruct b;
doSomething(a, &b); // you see a is input, b is output
1 голос
/ 16 марта 2010

Вы можете сделать следующее:

bool is_something_ok(int param,SomeStruct* p);

или

// return NULL if the operation failed.
Somestruct* do_work(int param);

Трудно сказать, является ли дизайн / API хорошим или плохим, нет ничего черного или белого ... (серый?!?!?)

Вы должны выбрать API / Standard, который будет проще для кода с.И будьте последовательны , если вы выберете первый тип метода, сделайте это для остальной части вашего проекта.

Не забудьте также , чтобы документировать ваш код , поэтомувам будет проще понять, как использовать ваш API.

1 голос
/ 16 марта 2010

Я думаю вернуть NULL, если что-то не в порядке и допустимо SomeStruct, если OK лучше в этом случае

SomeStruct* is_something_ok(int param);

В этом случае, кроме проверки логического значения, вы должны проверить, является ли оно НЕДЕЙСТВИТЕЛЬНЫМ, и если не использовать его.

Но есть случаи, когда нужно возвращать значение по параметру. Это зависит от количества возвращаемых значений, и можно использовать функцию контекста.

0 голосов
/ 16 марта 2010

Вам следует заглянуть в boost::optional, если вы хотите вернуть значение только в случае успеха.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...