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

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

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

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

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

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

Ответы [ 20 ]

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

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

1 голос
/ 19 февраля 2015

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

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

Конечно, есть аргумент для публичных API.Как некоторые DLL, предлагающие проверку на идиотизм.Вы знаете, эти аргументы: «Если пользователь вводит NULL, вы не хотите, чтобы ваше приложение зависало».Что за не аргумент.Именно пользователь передает поддельные данные в первую очередь;это явный выбор и ничего больше.Если вы чувствуете, что это качество, хорошо ... Я предпочитаю твердую логику и производительность по сравнению с такими вещамиКроме того, программист должен знать, что он делает.Если он работает с недопустимыми данными для конкретной области, то он не имеет права называть себя программистом.Я не вижу причин для снижения производительности, увеличения энергопотребления и увеличения размера двоичного кода, что, в свою очередь, влияет на кэширование инструкций и прогнозирование переходов в моих продуктах для поддержки таких пользователей.

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

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

Печально известный разгром glibc - это совсем другое.Злоупотребление привело к действительно полезному поведению для вызывающей стороны, и API оставался таким в течение десятилетий.Затем они изменили его.

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

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

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

0 голосов
/ 26 декабря 2010

Затраты времени разработки и производительности во время выполнения компромисса с надежностью API, который вы разрабатываете.

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

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

0 голосов
/ 09 декабря 2010

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

0 голосов
/ 09 декабря 2010

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

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

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

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

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

Я не думаю, что вызываемый абонент должен иметь дело с такими вещами

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

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

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

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

Конечно, здесь происходит компромисс, в зависимости от того, сколько на самом деле стоит вам чек. Возвращаясь к аналогии, предположим, что вы узнали, что тот же самый незнакомец медленно приближается к утесу на другом конце света, и что, потратив свои сбережения, чтобы прилететь туда и предупредить его, вы могли бы спасти его. Очень немногие люди будут судить вас очень строго, если в этой конкретной ситуации вы пренебрегаете этим (предположим, что телефон не был изобретен для целей этой аналогии). В терминах кодирования, однако, если проверка так же проста, как проверка на NULL, вы не можете сделать это, даже если «реальная» вина в ситуации лежит на вызывающей стороне.

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

По моему мнению, вызываемый абонент обязан исполнять свой контракт.

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

Как пользователь API, я хочу иметь возможность продолжать использовать его без аварийного завершения программы;Я хочу быть в состоянии выздороветь по крайней мере или изящно закрыться в худшем случае.

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