Нужны ли дублирующие проверки до вызова функции и в ней?
От: SomeOne_TT  
Дата: 11.09.06 08:55
Оценка:
У меня с одним коллегой возник теологический диспут...


Пример первый:

void foo(object &obj)
{
//передаем obj по ссылке и поэтому не проверяем его валидность,
//т.к. проверка на валидность делается один раз при создании объекта.

...
}


Пример второй:

bool foo(object *obj)
{
// проверяем каждый раз на валидность, т.к. это — указатель
if (!obj)
return false;

...
}

Первый вариант подразумевает проверку объекта на валидность при его создании.Функции, его использующие не производятт проверки.
Второй вариант подразумевает как проверку при создании, так и проверку в функциях, его использующих.



Какой их подходов вы считаете идеологически верным?
Re: Нужны ли дублирующие проверки до вызова функции и в ней?
От: absolute  
Дата: 11.09.06 10:12
Оценка: +3
Здравствуйте, SomeOne_TT, Вы писали:

SO_>Какой их подходов вы считаете идеологически верным?


Первый.
Re: Нужны ли дублирующие проверки до вызова функции и в ней?
От: fmiracle  
Дата: 11.09.06 10:37
Оценка:
Здравствуйте, SomeOne_TT, Вы писали:

SO_>Какой их подходов вы считаете идеологически верным?


Не совсем ясно. Если имеется в виду, что obj никак не должен быть null (то есть передача obj=null — это явная ошибка где-то), то лучше использовать модифицированный вариант второго подхода:
bool foo(object *obj)
{
    Assert( obj, "Assert violation: obj is null" );
}


Такой подход на этапе отладки даст понять, что что-то пошло в корне неверно и надо искать ошибку, в то время как просто второй метод — проглотит ошибку и она может проявиться в совершенно другом месте, и искать ее будет гораздо сложнее.
В релизе такую проверку можно выбросить или даже оставить (т.е. не пользоваться ASSERT, а самому написать проверку).
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Нужны ли дублирующие проверки до вызова функции и в ней?
От: gear nuke  
Дата: 11.09.06 11:11
Оценка:
Здравствуйте, SomeOne_TT, Вы писали:

[]

SO_>Первый вариант подразумевает проверку объекта на валидность при его создании.Функции, его использующие не производятт проверки.

SO_>Второй вариант подразумевает как проверку при создании, так и проверку в функциях, его использующих.

SO_>Какой их подходов вы считаете идеологически верным?


От контекста зависит. Например, библиотечные функции (вообще любой интерфейс предоставляемый "чужому" коду) как правило должны проверять входные параметры. Вот у printf неверный подход использовался

Хотя похоже, что в Вашем случае лучше первый вариант — когда при невозможности создать объект бросается исключение.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re: Нужны ли дублирующие проверки до вызова функции и в ней?
От: minorlogic Украина  
Дата: 11.09.06 11:31
Оценка:
Это вопрос не идеологический , а просто вопрос соглашений.

напрмиер если указатель проверяется на 0 , может его на 0xcdcdcdcd проверять и т.п ? Если же вы предполагаете что указатель пришедший в функцию обязан быть ненулевым , ставьте асерт и забывайте.
Ищу работу, 3D, SLAM, computer graphics/vision.
Re: Нужны ли дублирующие проверки до вызова функции и в ней?
От: Андрей Коростелев Голландия http://www.korostelev.net/
Дата: 11.09.06 11:35
Оценка: +1 -1
Здравствуйте, SomeOne_TT, Вы писали:

SO_>Пример первый:

SO_>void foo(object &obj)

SO_>Пример второй:

SO_>bool foo(object *obj)
SO_>{
SO_> if (!obj)
SO_> return false;
SO_>}

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

Если получение ф-ей foo нулевого указателя для тебя нормальное явление — используй вариант с указателем. Иначе используй передачу по ссылке или, как вариант, оберни это все в умный указатель, не допускающий нулевых значений.
-- Андрей
Re[2]: Нужны ли дублирующие проверки до вызова функции и в н
От: SomeOne_TT  
Дата: 11.09.06 12:34
Оценка:
Здравствуйте, Андрей Коростелев, Вы писали:


АК>Я думаю, ты сам ответишь на свой вопрос, после того как заметишь, что забота о валидности ссылки — задача вызывающегокода, то есть кода, формирующего эту ссылку, а в случае указателя проверка его валидности возлагается на использующий указатель код.


АК>Если получение ф-ей foo нулевого указателя для тебя нормальное явление — используй вариант с указателем. Иначе используй передачу по ссылке или, как вариант, оберни это все в умный указатель, не допускающий нулевых значений.



Ты наиболее полно озвучил агрументы моего оппонента.
Я же считаю, что проверка входных параметров в любом случае — необходимое дело.И в первом и во втором случаях проверка имхо необходима.
Данный код может быть использован иным программсистом в ином месте, причем входная проверка может быть пропущена.
В таком случае вызов функции может обрушить программу. Я же думаю, что в любом случае функция должна вернуть код возврата, а не перекладывать обработку ошибок на вызывающую сторону или систему.
Re[3]: Нужны ли дублирующие проверки до вызова функции и в н
От: Андрей Коростелев Голландия http://www.korostelev.net/
Дата: 11.09.06 12:55
Оценка:
Здравствуйте, SomeOne_TT, Вы писали:

SO_>Ты наиболее полно озвучил агрументы моего оппонента.

SO_>Я же считаю, что проверка входных параметров в любом случае — необходимое дело.И в первом и во втором случаях проверка имхо необходима.

В случае ссылки, попытка разыменования нулевого указателя для передачи в ф-ю приведет к UB в вызывающем коде. То есть проверять ссылку на неравенство нулю внутри foo функции уже нет смысла.

Насчет использования assert-ов или исключений/кодов возврата для проверки валидности уазателей: assert следует использовать когда входные данные (аргументы ф-и) пришли к тебе из надежного источника, иначе ограничься исключением или кодом возврата. Степень надежности ты должен определять сам. К примеру, для методов публичного интерфейса более логично использовать исключений/кодов возврата, assert-ы же использовать внутри класса.
-- Андрей
Re: Нужны ли дублирующие проверки до вызова функции и в ней?
От: Beam Россия  
Дата: 11.09.06 14:26
Оценка: +1
Здравствуйте, SomeOne_TT, Вы писали:

SO_>Первый вариант подразумевает проверку объекта на валидность при его создании.Функции, его использующие не производятт проверки.

SO_>Второй вариант подразумевает как проверку при создании, так и проверку в функциях, его использующих.

SO_>Какой их подходов вы считаете идеологически верным?


Первый. За передаваемые параметры должен отвечать вызывающий код.

И вот мои аргументы:
1. Как выглядят проверки в вызывающем коде?.
В первом случае надо проверять obj перед вызовом, во втором — результат foo() после вызова. Первый вариант предпочтителен, т.к. второй вариант заставляет задумываться о смысле значения, возвращенного foo().
2. Если вызывающий код не обрабатывает ошибку.
Первый вариант вызывает исключение и программист может сразу локализовать ошибку. При втором варианте программа продолжает работу фактически не выполнив foo(). Это может вылиться в проблемы при дальнейшей работе. Такую ошибку найти намного труднее.
3. Если вызывающий код предусмотрел обработку ошибки.
Код, перехватывающий ошибку в первом случае выглядит как try-catch, во втором как if. На мой взгляд try-catch больше воспринимается как обработчик ошибок.

По всем трем пунктам первый вариант предпочтительней.

Для методов, возвращающих значения, можно сделать так:
func();                        // при ошибке кидает исключение
funcOrDefault();    // при ошибке возвращает какое-либо значение


Пусть программист сам сделает выбор в зависимости от контекста.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Best regards, Буравчик
Re[2]: Нужны ли дублирующие проверки до вызова функции и в н
От: SomeOne_TT  
Дата: 11.09.06 17:10
Оценка:
Здравствуйте, Beam, Вы писали:

B>По всем трем пунктам первый вариант предпочтительней.


Что же.
Beam и Андрей Коростылев, вы меня убедили в верности первого варианта, хотя я был сторонником второго.
Спасибо.
Re[3]: Нужны ли дублирующие проверки до вызова функции и в н
От: fmiracle  
Дата: 11.09.06 19:35
Оценка: +1
Здравствуйте, SomeOne_TT, Вы писали:

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


Вообще-то код возврата — это и есть переложение обработки ошибок на вызывающую сторону, причем прямо в точку вызова.
Это
1. Неудобно — при вызове нескольких функций, тем более зависящих друг от друга придется в вызывающем коде громоздить проверку на проверке
2. Код возврата очень легко проигнорировать или неполностью проверить... Что приводит к блуждающим ошибкамм.

в-общем, исклчюения не просто так придумывали...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Нужны ли дублирующие проверки до вызова функции и в ней?
От: bkat  
Дата: 11.09.06 20:08
Оценка: +1
Здравствуйте, SomeOne_TT, Вы писали:


SO_>Какой их подходов вы считаете идеологически верным?


Почему должен быть обязательно один подход идеологически верным?
Ну нету, за исключением тривиальных случаев, одного, единственного верного подхода.
Re[2]: Нужны ли дублирующие проверки до вызова функции и в н
От: ssianky Молдова  
Дата: 12.09.06 06:57
Оценка:
Здравствуйте, bkat, Вы писали:

SO_>>Какой их подходов вы считаете идеологически верным?


B>Почему должен быть обязательно один подход идеологически верным?

B>Ну нету, за исключением тривиальных случаев, одного, единственного верного подхода.

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

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

на мой взгляд, указатели имеет смысл использовать только для передачи объекта от одной сущности к другой и, конечно, в C.

(чтобы было понятно. это я поспорил с Алексеем () об этом)
Re: Нужны ли дублирующие проверки до вызова функции и в ней?
От: klopodav  
Дата: 12.09.06 11:12
Оценка: 1 (1)
SO_>Какой их подходов вы считаете идеологически верным?

Общая рекомендация примерно такая (конечно, не на все случаи жизни, но на многие):

Если obj-входной параметр (т. е. не меняется в функции), то лучше передать его по константной ссылке:

void foo(const object &obj)


Если obj-выходной параметр, то передать его по указателю и обязательно проверить, причем если он не валиден, лучше кинуть какое-нибудь исключение (Использовать возвращаемое значение для невалидного указателя допустимо, разве что, когда наша функция — operator() и используется как предикат для поиска в контейнере). Проверка может быть как постоянной, так и включенной только в дебаге — в зависимости от решаемой задачи:
#define MY_ASSERT(ptr) { if(!(ptr)) {throw MyException("тухлый указатель!"); } }

bool foo(object *obj)
{
// проверяем каждый раз на валидность, т.к. это — указатель
    MY_ASSERT(obj)
}


Если obj-входной параметр, и нет возможности передать его по ссылке, то передать по константному указателю с проверкой::
bool foo(const object *obj)
{
// проверяем каждый раз на валидность, т.к. это — указатель
    MY_ASSERT(obj)
}
Re: Нужны ли дублирующие проверки до вызова функции и в ней?
От: Mamut Швеция http://dmitriid.com
Дата: 15.09.06 13:31
Оценка:
Здравствуйте, SomeOne_TT, Вы писали:

SO_>У меня с одним коллегой возник теологический диспут...



SO_>Пример первый:


SO_>void foo(object &obj)

SO_>{
SO_> //передаем obj по ссылке и поэтому не проверяем его валидность,
SO_> //т.к. проверка на валидность делается один раз при создании объекта.

SO_> ...

SO_>}


SO_>Пример второй:


SO_>bool foo(object *obj)

SO_>{
SO_> // проверяем каждый раз на валидность, т.к. это — указатель
SO_> if (!obj)
SO_> return false;

SO_> ...

SO_>}

SO_>Первый вариант подразумевает проверку объекта на валидность при его создании.Функции, его использующие не производятт проверки.

SO_>Второй вариант подразумевает как проверку при создании, так и проверку в функциях, его использующих.

Второй способ называется defensive programming (или, возможно, "параноидальное" программирование )

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

Другой вопрос — что есть данные и что есть точка входа? И что делать с данными, которые манипулируются всеми, кем только можно, и в какой-то момент могут стать невалидными?

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

В нашем случае:
void foo(object &obj)
{
    //передаем obj по ссылке и поэтому не проверяем его валидность, 
    //т.к. проверка на валидность делается один раз при создании объекта.

   ...
}


В момент создания объекта он "входит в систему". То есть для foo он уже должен быть гарантированно валидным.

Ну и конечно здесь
Автор: Beam
Дата: 11.09.06
.
... << RSDN@Home 1.2.0 alpha rev. 655>>


dmitriid.comGitHubLinkedIn
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.