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

Хорошая конструкция для возврата значения по параметру?

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

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

BTW: Есть ли авторитетная книга/статья о дизайне API?

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

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

Ответ 3

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

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

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

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

Ответ 4

Я бы сказал, это зависит. Насколько дорогой ваш тип для копирования конструкции? Можете ли вы написать свою функцию RVO - дружелюбно? По крайней мере, пока у нас нет С++ 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 начнет работать, но по моему опыту это не то, на что вы обычно можете положиться.

Ответ 5

Относительно вашего вопроса о книге о дизайне API. Ищите "API Design for С++" Мартина Редди, который был опубликован в 2011 году.

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

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

Ответ 6

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

SomeStruct* is_something_ok(int param);

В этом случае, кроме проверки логического значения, вы должны проверить, является ли он NULL, и если не использовать его.

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

Ответ 7

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

bool is_something_ok(int param,SomeStruct* p);

или

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

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

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

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

Ответ 8

Я бы предложил вернуть Тип результата прямо так:

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

Ответ 9

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