Уважаемые гуру скажите как делать лучше (быстрее,избавляло от ошибок)
должно копмилится VC7.1
// раньше я делал такinline int TestOld(int *A)
{
// захотел избавится от этогоif(NULL==A) return 0;
return *A;
}
// получилось такinline int TestNeed(const int &A)
{
return A;
}
// но оказалось что если вызвать такоеint *test=NULL;
TestNeed(*test);// краш// надо ли защищаться от подобных ошибок ?inline int TestNew(const int &A)
{
// получается что нужно так ?if(NULL==&A)return 0;
return A;
}
... << RSDN@Home 1.1.4 @@subversion >>
Re: передача параметра по ссылке ?
От:
Аноним
Дата:
18.10.04 14:31
Оценка:
Если есть вероятность, что будет передан null-указатель, то следует использовать тип параметра "int *", так как сразу видно, что фукция ожидает такие указатели и может с ними работать. Если функция принимает параметр-ссылку, то передача null — это ошибка вызывающего, т.к. эта функция не рассчитана на такое использование. Ссылка — это тот же указатель, но обязательно инициализированный. Получение NULL-ссылок возможно, но противоречит их назначению. Код проверки
if(NULL==&A)return 0;
выглядит неестественно, хотя и работоспосбен.
Резюме:
если функция ожидает NULL-указателей, то параметром должен быть указатель
если параметр — ссылка, то функция не ожидает null-указателей и можно смело "падать" на NULL-ссылках, так как это "неправильные" ссылки, которые делают неправильный мед. В _DEBUG версии можно ASSERT поставить
Если ты имеешь дело с указателями, и возможна ситуация, когда указатель может быть нулевым, то без проверок не обойтись, и ничего страшного в том, как реализована TestOld, нет. Более того, пытаться в такой ситуации использовать TestNew опасно, т.к. запись
int *test=NULL;
TestNeed(*test);// краш
ведет к неопределенному поведению из-за попытки разыменовывания нулевого указателя (поэтому проверка if(NULL==&A) тебе в общем случае не поможет).
Если так хочется убрать провекру из TestOld — надо пересмотреть дизайн и/или реадизацию, чтобы исключить перелачу нулевого указателя в эту функцию.
Здравствуйте, DoС, Вы писали:
DoС>Уважаемые гуру скажите как делать лучше (быстрее,избавляло от ошибок)
Если передача нулевого указателя в функцию — это фича, то и надо передавать указатель.
В крайнем случае, завести второй параметр — флажок.
А если нулевые указатели не должны туда попадать, то пусть будет ссылка.
Поскольку разыменование нулевого указателя — само по себе неопределённое поведение (частный случай которого — твой ASSERT в недрах библиотечной функции), можешь умыть руки.
В отладочных целях, да и из соображений чистоты, попробуй переехать на умные указатели.
В этом случае ASSERT переезжает из функции прямо в оператор разыменования, то есть туда, где причина, а не следствие беды.
template<class T>
class some_smart_ptr
{
T* p_;
...
public:
T* operator->() const { assert(p_); return p_; } // оператор доступа к членам объекта
T& operator*() const { assert(p_); return *p_; } // оператор доступа к самому объекту
...
// заметь, что можно не открывать оператор приведения к голому указателю, во избежание соблазнов#if 0
operator T*() const { return p_; }
#endif
...
};
И вообще, можно сделать умный указатель, который не принимает нулевые значения.
Здравствуйте, DoС, Вы писали:
DoС>Уважаемые гуру скажите как делать лучше (быстрее,избавляло от ошибок) DoС>должно копмилится VC7.1
DoС>
DoС>// раньше я делал так
DoС>inline int TestOld(int *A)
DoС>{
DoС> // захотел избавится от этого
DoС> if(NULL==A) return 0;
DoС> return *A;
DoС>}
DoС>// получилось так
DoС>inline int TestNeed(const int &A)
DoС>{
DoС> return A;
DoС>}
DoС>// но оказалось что если вызвать такое
DoС>int *test=NULL;
DoС>TestNeed(*test);// краш
DoС>// надо ли защищаться от подобных ошибок ?
а нужно ли защищаться от подобных ошибок:
[ccode]
char* str = NULL;
char c = str[0];
c = *str;
DoС>inline int TestNew(const int &A) DoС>{ DoС> // получается что нужно так ? DoС> if(NULL==&A)return 0; DoС> return A; DoС>} DoС>[/ccode]
нет, не получается, ссылки тут не причем. Если ты пользуешься ссылкой, то зачем тогда строить указатель ( test ). пусть это будет автоматическая переменная, ссылку на которую ты с успехом передашь.
Will I live tomorrow? Well I just can't say
But I know for sure — I don't live today.
Jimi Hendrix.
Здравствуйте, Аноним, Вы писали:
А>Получение NULL-ссылок возможно, но противоречит их назначению. Код проверки А>if(NULL==&A)return 0; А>выглядит неестественно, хотя и работоспосбен.
Неверно. Получение NULL-ссылок — это неопределенное поведение, поскольку требует разыменовывания нудевого указателя.
Здравствуйте, DoС, Вы писали:
DoС>Уважаемые гуру скажите как делать лучше (быстрее,избавляло от ошибок)
от ошибок в ДНК не избавишься
DoС>// но оказалось что если вызвать такое DoС>int *test=NULL; DoС>TestNeed(*test);// краш
DoС>// надо ли защищаться от подобных ошибок ?
нет, не нужно
ибо ссылка может быть привязана только к объекту, объектов же с нулевым адресом не бывает.
и вся тяжесть ответственности в данном случае лежит на вызывающей стороне.
а уж разывменование нулевого указателя — здесь вообще диск будет отформатирован раньше, чем управление будет передано в твою функцию.
И еще посмотри, например, на стандартные функции работы со строками типа strlen: в них нельзя передавать нулевой указатель, но они ничего не проверяют — это записано в документации