Непустой выходной параметр - ваша реакция?
От: Basil2 Россия https://starostin.msk.ru
Дата: 22.03.17 11:55
Оценка: 1 (1)
Есть функция:
result_code GetSomething(vector<Something>& output);


При одном из вызовов функции передается непустой вектор. Как, на ваш взгляд, функция должна отреагировать на это?

1. Всегда очищать (лишнее действие, что не в духе плюсов).
2. Игнорировать, т.е. новые значения добавятся к старым ("не очистил сам дурак" — вполне в духе, но добавляет нестабильности).
3. Должен сработать assert (типа assert(output.empty)).
4. Вернуть ошибку/бросить исключение.
5. Оставлю комментарий со своим вариантом.

(Хотел сделать настоящее голосование, но получаю "500 — Internal server error". Зато здесь можно обсудить более развернуто).

Что скажете?
Проект Ребенок8020 — пошаговый гайд как сделать, вырастить и воспитать ребенка.
Отредактировано 23.03.2017 11:54 Basil2 (мелкая поправка) . Предыдущая версия .
Re: Непустой выходной параметр - ваша реакция?
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 22.03.17 12:04
Оценка: +2
Здравствуйте, Basil2, Вы писали:

B>1. Всегда очищать (лишнее действие, что не в духе плюсов).

B>2. Игнорировать, т.е. новые значения добавятся к старым ("не очистил сам дурак" — вполне в духе, но добавляет нестабильности).
B>3. Должен сработать assert (типа assert(!output.empty)).
Если 2 не подходит, то тогда 3.
Sic luceat lux!
Re: Непустой выходной параметр - ваша реакция?
От: RedApe Беларусь  
Дата: 22.03.17 12:07
Оценка: -2
Здравствуйте, Basil2, Вы писали:

B>1. Всегда очищать (лишнее действие, что не в духе плюсов).


 output.swap(internal_buffer);


никаких лишних действий
--
RedApe
Отредактировано 22.03.2017 12:08 RedApe . Предыдущая версия .
Re: Непустой выходной параметр - ваша реакция?
От: SaZ  
Дата: 22.03.17 12:09
Оценка: 1 (1) +1
Здравствуйте, Basil2, Вы писали:

B>Есть функция:

B>
B>result_code GetSomething(vector<Something>& output);
B>


B>При одном из вызовов функции передается непустой вектор. Как, на ваш взгляд, функция должна отреагировать на это?


B>1. Всегда очищать (лишнее действие, что не в духе плюсов).


В этом случае делаем vector<Something> GetSomething( result_code *res = nullptr );

B>2. Игнорировать, т.е. новые значения добавятся к старым ("не очистил сам дурак" — вполне в духе, но добавляет нестабильности).


Нужно или документировать или придумать нормальное имя функции, в зависимости от решаемой задачи. Например: AppendSomething / GetSomething.
Вообще, это плохой паттерн. Потому что не понятно, что делать с контейнером в случае ошибки — откатывать изменения или нет.
Имхо, если что-то надо добавить в контейнер, то на вход функции надо передавать итератор.

B>3. Должен сработать assert (типа assert(!output.empty)).


Нет, ибо это работает только при отладке. Для проектов, где только 1 программист это может и прокатит. Но в целом — ассерт должен быть лишь дополнением к логике, чтобы раньше понять где ошибка.

B>4. Вернуть ошибку/бросить исключение.


Как захотите.
Отредактировано 22.03.2017 12:10 SaZ . Предыдущая версия .
Re: Непустой выходной параметр - ваша реакция?
От: uzhas Ниоткуда  
Дата: 22.03.17 12:10
Оценка: +2
Здравствуйте, Basil2, Вы писали:

B>Что скажете?


если параметр чисто out, а не in/out, то я бы предложил следующее поведение
1) если функция отрабатывает успешно, то помещает результат в output таким образом, чтобы output в точности содержал результат и ничего лишнего (как вы этого добьетесь — неважно. вы можете clear вызывать, вы можете делать туда move/swap из другого вектора)
2) если функция возвращает ошибку, то output содержит неопределенное значение после возварата из функции. то есть тот, кто вызывал функцию не имеет права читать из output элементы, т.к. не знает какие они там. еще лучше, если функция оставит output нетронутым


если смысл функции что-то _добавлять_ в output, то, очевидно, мой совет уже будет неактуален
Re: Непустой выходной параметр - ваша реакция?
От: frymode  
Дата: 22.03.17 12:10
Оценка:
Здравствуйте, Basil2, Вы писали:

B>При одном из вызовов функции передается непустой вектор. Как, на ваш взгляд, функция должна отреагировать на это?


B>1. Всегда очищать (лишнее действие, что не в духе плюсов).


Почему не в духе? Из того, что есть в стандартной библиотеке, с ходу вспомнился такой вполне себе рабочий паттерн:

std::string input;
while (std::getline(std::cin, input)) { ... }
Re: Непустой выходной параметр - ваша реакция?
От: Erop Россия  
Дата: 22.03.17 12:11
Оценка: +1
Здравствуйте, Basil2, Вы писали:

B>Есть функция:

B>
B>result_code GetSomething(vector<Something>& output);
B>


B>При одном из вызовов функции передается непустой вектор. Как, на ваш взгляд, функция должна отреагировать на это?


B>1. Всегда очищать (лишнее действие, что не в духе плюсов).

B>2. Игнорировать, т.е. новые значения добавятся к старым ("не очистил сам дурак" — вполне в духе, но добавляет нестабильности).
B>3. Должен сработать assert (типа assert(!output.empty)).
B>4. Вернуть ошибку/бросить исключение.
B>5. Оставлю комментарий со своим вариантом.

B>(Хотел сделать настоящее голосование, но получаю "500 — Internal server error". Зато здесь можно обсудить более развернуто).


B>Что скажете?


1.1) Часто так бывает, что "лишнего действия" нет, например мы где-то в GetSomething пишем:
const vector<Something>& res = lookupRes(...);
output = res;
// тут ещё может какая фильтрация там, или обработка output
или что-то вроде
output = vector<Something>( iterBrginn, iterEnd );

2.1) Добавлять новые к старым, только функцию назвать AddSomething
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Непустой выходной параметр - ваша реакция?
От: Carc Россия https://vk.com/gosha_mazov
Дата: 22.03.17 12:18
Оценка: 4 (1) +2
Здравствуйте, Basil2, Вы писали:

B>Есть функция:

B>
B>result_code GetSomething(vector<Something>& output);
B>


B>При одном из вызовов функции передается непустой вектор. Как, на ваш взгляд, функция должна отреагировать на это?


B>1. Всегда очищать (лишнее действие, что не в духе плюсов).

B>2. Игнорировать, т.е. новые значения добавятся к старым ("не очистил сам дурак" — вполне в духе, но добавляет нестабильности).
B>3. Должен сработать assert (типа assert(!output.empty)).
B>4. Вернуть ошибку/бросить исключение.
B>5. Оставлю комментарий со своим вариантом.

B>(Хотел сделать настоящее голосование, но получаю "500 — Internal server error". Зато здесь можно обсудить более развернуто).


B>Что скажете?

Функцию result_code GetSomething(vector<Something>& output); сделать закрытой, а еще лучше для читабельности кода, переименовать ее в GetSomething_Internal и добавить в нее еще один параметр (const bool bClear), который будет контролировать пустой ли пришел входной вектор (true — обязан быть пустым, false — нет).

А теперь главное:
К ней 2 фасадных, открытых функции GetSomething_WithClear(…) и GetSomething_WithoutClear()

Соответственно, первая GetSomething_WithClear очищает входной вектор, и передает во внутреннюю, вторая не очищает и передает во внутреннюю GetSomething_Internal.

Т.е. в самой внутренней функции GetSomething_Internal логика должна быть четко согласована, пустой вектор аль нет.

Интерфейсные открытые функции GetSomething_WithClear|WithoutClear служит единственной точкой доступа, мимо них не проскочишь.

Ну а названия в функциях WithClear|WithoutClear явно говорят, что мы хотим.

По моему такой код явно выражает намерения, он читабелен и понятен, и легок в поддержке (пустой\не пустой вектор контроллируется в 2-ух открытых фасадных функциях).

А что конкретно нужно делать: бросать исключение, ассертить, ассертить и бросать, и прочия это уже от задачи зависит.

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

Дык вот какая-нить функция вида ОтдайПапку (путь) откуда работает экзешник непонятно что должна делать? Отдать просто путь, или путь со слешом на конце (ну например для поиска каких-то файлов в своей папке).

Вот что б не гадать, и каждый раз не лазить в функцию ОтдайПапку (путь) на предмет со слешом на конце аль нет, давным-давно было переписано в таком же стиле

То бишь
ОтдайПапку_(путь)_Без_слеша
ОтдайПапку_(путь)_Со_Слешом

Дергают они одну и ту же private функцию, а на выходе аккуратненько подчищают что надо (удаляют, добавляют слеш).

И всё. И горя не знаю. Все ясно, понятно, и уже не "легко в поддержке", а ее и вовсе больше не нужно.
Aml Pages Home
Отредактировано 22.03.2017 16:42 Carc . Предыдущая версия .
Re[2]: Непустой выходной параметр - ваша реакция?
От: Erop Россия  
Дата: 22.03.17 12:59
Оценка:
Здравствуйте, RedApe, Вы писали:


RA>
RA> output.swap(internal_buffer);
RA>


RA>никаких лишних действий


1) заводишь лишний объект
2) Если функция используется в виде
vector<Something> dst;
for( ... ) {
    dst.clean();
    GetXXX( dst );
    ProcessXXX( dst );
}
то в твоей реализации не будет переиспользоваться аллокированный в dst буффер.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Непустой выходной параметр - ваша реакция?
От: Erop Россия  
Дата: 22.03.17 13:03
Оценка:
Здравствуйте, SaZ, Вы писали:

B>>1. Всегда очищать (лишнее действие, что не в духе плюсов).

SaZ>В этом случае делаем vector<Something> GetSomething( result_code *res = nullptr );

Зато пессимизация...

SaZ>Вообще, это плохой паттерн. Потому что не понятно, что делать с контейнером в случае ошибки — откатывать изменения или нет.

+1, и в варианте 1 та же проблема.

SaZ>Имхо, если что-то надо добавить в контейнер, то на вход функции надо передавать итератор.

Как это избавит от проблем с тем, что надо откатывать?

SaZ>Нет, ибо это работает только при отладке. Для проектов, где только 1 программист это может и прокатит. Но в целом — ассерт должен быть лишь дополнением к логике, чтобы раньше понять где ошибка.

Можно использовать на проекте более умную библиотеку assert'ов...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Непустой выходной параметр - ваша реакция?
От: VsevolodC Россия  
Дата: 22.03.17 13:35
Оценка:
Здравствуйте, Basil2, Вы писали:

B>Есть функция:

B>
result_code GetSomething(vector<Something>& output);

B>При одном из вызовов функции передается непустой вектор. Как, на ваш взгляд, функция должна отреагировать на это?
B>2. Игнорировать, т.е. новые значения добавятся к старым ("не очистил сам дурак" — вполне в духе, но добавляет нестабильности).
B>4. Вернуть ошибку/бросить исключение.

комбинация 2 и 4 — при передаче пустого и непустого вектора возвращаются разные result_code
Re[3]: Непустой выходной параметр - ваша реакция?
От: SaZ  
Дата: 22.03.17 14:18
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, SaZ, Вы писали:


B>>>1. Всегда очищать (лишнее действие, что не в духе плюсов).

SaZ>>В этом случае делаем vector<Something> GetSomething( result_code *res = nullptr );

E>Зато пессимизация...


Даже если не сработает RVO, не думаю, что накладные расходы на вызов конструктора перемещения будут критичны.

SaZ>>Вообще, это плохой паттерн. Потому что не понятно, что делать с контейнером в случае ошибки — откатывать изменения или нет.

E>+1, и в варианте 1 та же проблема.

В большинстве случаев я не заморачиваюсь и использую промежуточные контейнеры. Загоняюсь об оптимизациях только если функцию нужно дёргать ну уж совсем часто.
И, насколько я понимаю, для всяких контейнеров типа list/deque конкатенация может выполниться практически без оверхеда.

SaZ>>Имхо, если что-то надо добавить в контейнер, то на вход функции надо передавать итератор.

E>Как это избавит от проблем с тем, что надо откатывать?

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

Я думаю эта проблема есть почти везде. Я стараюсь делать код в первую очередь читаемым и с предсказуемым поведением (надёжным). И только когда возникает реальная проблема — начинаю думать об оптимизациях.

SaZ>>Нет, ибо это работает только при отладке. Для проектов, где только 1 программист это может и прокатит. Но в целом — ассерт должен быть лишь дополнением к логике, чтобы раньше понять где ошибка.

E>Можно использовать на проекте более умную библиотеку assert'ов...

Понятно, что так и делается. Но всё равно, использование ассертов для программирования логики не стоит. Уж лучше исключения кидать.
Re[4]: Непустой выходной параметр - ваша реакция?
От: Erop Россия  
Дата: 22.03.17 14:28
Оценка: +1
Здравствуйте, SaZ, Вы писали:

SaZ>Даже если не сработает RVO, не думаю, что накладные расходы на вызов конструктора перемещения будут критичны.

Пессимизация тут в другом месте сидит. Если ты этот get делаешь в цикле, например у разных объектов, то не будет переиспользоваться буфер.


SaZ>Не избавит. Тут либо хорошо продумывать логику, либо использовать промежуточные контейнеры. В первом случае нужно следить за кодом, во втором код будет чище, но хуже по производительности.


Для оригинальной версии есть хорошее решение. Если вернули ошибку, то содержимое output произвольное корректное.

SaZ>Я думаю эта проблема есть почти везде. Я стараюсь делать код в первую очередь читаемым и с предсказуемым поведением (надёжным). И только когда возникает реальная проблема — начинаю думать об оптимизациях.


Ну есть разные варианты как сделать. Если есть несколько разных, то лучше выбрать более эффективный

SaZ>Понятно, что так и делается. Но всё равно, использование ассертов для программирования логики не стоит. Уж лучше исключения кидать.

IMHO, это лучше отдать на откуп библиотеке обработке ошибок и assert'ов.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Непустой выходной параметр - ваша реакция?
От: antropolog  
Дата: 22.03.17 14:33
Оценка: 2 (1) +1
Здравствуйте, Basil2, Вы писали:

B>2. Игнорировать, т.е. новые значения добавятся к старым ("не очистил сам дурак" — вполне в духе, но добавляет нестабильности).


B>Что скажете?


в конкретно данном примере вот это. Инвариант пустой/непустой входной вектор это не этой функции дело. Вдруг я эти something'и собираю из десяти разных мест десятью разными методами в этот вектор, и тут какой-нибудь из методов решил его "очистить", wtf!??
p.s. для более явного выражения семантики из п2. я бы назвал ф-цию PopulateWithSomething
Отредактировано 22.03.2017 14:35 antropolog . Предыдущая версия .
Re: Непустой выходной параметр - ваша реакция?
От: viellsky  
Дата: 22.03.17 14:36
Оценка: +4
Здравствуйте, Basil2, Вы писали:

B>Есть функция:

B>
B>result_code GetSomething(vector<Something>& output);
B>


B>1. Всегда очищать (лишнее действие, что не в духе плюсов).

С таким названием функции — только так.

B>2. Игнорировать, т.е. новые значения добавятся к старым ("не очистил сам дурак" — вполне в духе, но добавляет нестабильности).

Это уже не Get, а Append.

B>3. Должен сработать assert (типа assert(!output.empty)).

B>/бросить исключение.
Это зависит от того, как построен процесс тестирования и как организована обработка исключительных ситуаций. Но в общем случае я бы не заморачивался.

B>4. Вернуть ошибку

Бессмысленно — если кто и будет озабочиваться обработкой кодов возврата — то прочитает хелп к функции/кодам возврата — и узнает о том, что этот Гет "настоящий" (т.е. с предварительной очисткой).
Re: Непустой выходной параметр - ваша реакция?
От: kov_serg Россия  
Дата: 22.03.17 14:47
Оценка: -1 :)
Здравствуйте, Basil2, Вы писали:

B>Есть функция:

B>
B>result_code GetSomething(vector<Something>& output);
B>


B>При одном из вызовов функции передается непустой вектор. Как, на ваш взгляд, функция должна отреагировать на это?


B>1. Всегда очищать (лишнее действие, что не в духе плюсов).


Точно не в духе. В C++ надо писать так
template<class T> result_code GetSomething(T output);
Re[2]: Непустой выходной параметр - ваша реакция?
От: andyp  
Дата: 22.03.17 15:04
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>Точно не в духе. В C++ надо писать так

_>
_>template<class T> result_code GetSomething(T output);
_>


Так ты на выходе ничего не получишь кроме result_code. Так что функцию придется переименовать в GetNothing.
Re: Непустой выходной параметр - ваша реакция?
От: andyp  
Дата: 22.03.17 15:09
Оценка: :)
Здравствуйте, Basil2, Вы писали:

B>Что скажете?


Неконстантная ссылка на входе — у тебя руки развязаны , так что все прокатит. Только назови функцию соответствующим образом, чтобы минимизировать сюрпризы для вызывающей стороны.
Re[3]: Непустой выходной параметр - ваша реакция?
От: B0FEE664  
Дата: 22.03.17 16:42
Оценка:
Здравствуйте, andyp, Вы писали:

A>Так ты на выходе ничего не получишь кроме result_code. Так что функцию придется переименовать в GetNothing.


auto r =  GetSomething< vector<Something>& >(output);

И каждый день — без права на ошибку...
Re: Непустой выходной параметр - ваша реакция?
От: B0FEE664  
Дата: 22.03.17 16:49
Оценка: +1
Здравствуйте, Basil2, Вы писали:

B>Есть функция:

B>
B>result_code GetSomething(vector<Something>& output);
B>


B>Что скажете?

При наличии неизменной и полной документации для меня приемлем любой из вариантов, вплоть до того, что очистка output может зависеть от возвращаемого кода результата.
Удобным же считаю вариант описанный у Carc'a.
И каждый день — без права на ошибку...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.