В C или C ++ я должен проверить параметры указателя на NULL / nullptr? - PullRequest
37 голосов
/ 08 декабря 2010

Этот вопрос был вдохновлен этим ответом .

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

Все, что не определено, не определено.

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

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

Ответы [ 20 ]

42 голосов
/ 08 декабря 2010

Если вы собираетесь проверять аргументы указателя NULL, в которых вы не заключили контракт, чтобы принять и интерпретировать их, сделайте это с assert, а не с условной ошибкой возврата. Таким образом, ошибки в вызывающей стороне будут немедленно обнаружены и могут быть исправлены, что позволяет легко отключать служебные данные в производственных сборках. Я ставлю под сомнение значение assert за исключением документации, однако; ошибка от разыменования NULL-указателя также эффективна для отладки.

Если вы возвращаете код ошибки вызывающей стороне, у которой уже зарекомендовал себя с ошибкой , наиболее вероятным результатом будет то, что вызывающая сторона проигнорирует ошибку, и плохие вещи произойдут намного позже, когда Первоначальная причина ошибки стала трудно или невозможно отследить. Почему разумно предположить, что вызывающая сторона проигнорирует возвращаемую ошибку? Поскольку вызывающий уже проигнорировал возвращаемое сообщение об ошибке malloc или fopen или какую-либо другую библиотечно-распределительную функцию, которая возвратила NULL, чтобы указать на ошибку!

28 голосов
/ 08 декабря 2010

В C ++, если вы не хотите принять указатели NULL, тогда не рискуйте : вместо этого примите ссылку.

14 голосов
/ 08 декабря 2010

Хотя в общем случае я не вижу смысла в определении NULL (почему NULL, а не какой-то другой недопустимый адрес?) Для публичного API, я, вероятно, все еще буду делать это просто потому, что многие программисты на C и C ++ ожидают такого поведения.

8 голосов
/ 08 декабря 2010

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

Вы можете документировать договор до тех пор, пока вы не покраснете, но вы не можете в коде вызываемого абонента предотвратить неоправданное или злонамеренное неправильное использование вашей функции.Решение, которое вы должны принять, - это вероятная цена неправильного использования.

6 голосов
/ 08 декабря 2010

На мой взгляд, это не вопрос ответственности. Это вопрос надежности.

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

4 голосов
/ 08 декабря 2010

Моя философия такова: ваши пользователи должны допускать ошибки, а ваша команда программистов не должна.

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

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

Если вы пишете API, то только функции верхнего уровня должны отлавливать и обрабатывать неверный ввод. Бессмысленно продолжать проверять NULL-указатель на три или четыре уровня глубоко в стеке вызовов.

4 голосов
/ 08 декабря 2010

Ответ будет разным для C и C ++.

C ++ имеет ссылки. Единственная разница между передачей указателя и передачей ссылки состоит в том, что указатель может быть нулевым. Итак, если автор вызываемой функции ожидает аргумент-указатель и забывает сделать что-то вменяемое, когда оно пустое, он глуп, сумасшедший или пишет C-with-классы.

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

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

4 голосов
/ 08 декабря 2010

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

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

3 голосов
/ 08 декабря 2010

Я за защитное программирование.

Если вы не можете профилировать, что эти nullptr проверки происходят в узком месте вашего приложения ... (в таких случаях вполне возможно, что в этих точках не следует проводить тесты значений этих указателей)

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

итак: проверьте свои указатели на NULL!

1 голос
/ 08 декабря 2010

Для C ++, если ваша функция не принимает нулевой указатель, используйте аргумент ссылки. В общем.

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

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

Приветствия и hth.,

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