NullPointerException
s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException
. Они наиболее распространены, но другие способы перечислены на странице NullPointerException
javadoc.
Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException
, be:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
В первой строке внутри main
я явно устанавливаю ссылку Object
obj
равной null
. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException
, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.
(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)
Предпочтите RAII.
автоматический STL (и совместно использованный в повышении & C++ 0x), указатели могут помочь.
Фигурные скобки потребовали, если у Вас есть больше чем один шаг добавления отступа:
if (bla) {
for (int i = 0; i < n; ++i)
foo();
}
Это помогает сохранить добавление отступа в соответствии с тем, как компилятор видит код.
Вероятно, легкая задача, но тем не менее важное правило:
Избегают неопределенного поведения.
существует очень многое из него в C++, и, вероятно, невозможно записать нетривиальное приложение, которое не зависит от него так или иначе, но общее правило должно все еще быть "неопределенным поведением, плохо". (Поскольку печально существуют программисты на C++ там, кто чувствует, что "это работает над моей машиной/компилятором", достаточно хорошо).
, Если необходимо полагаться на него, проясните всем что, почему, где и как.
Точка должна быть выделена для объяснения различия между семантикой значения и семантикой объекта. Это могло обеспечить типичные фрагменты кода о том, как копия обрабатывается, различные случаи.
См. также Контрольный список для записи копии constuctor и оператора присваивания в C++
Безотносительно инструкций сделайте его очень легким для распознавания применимости: чем меньше выбора Вы имеете, тем меньше времени Вы освобождаете выбор. И более легкое это становится к brainparse кодом.
Примеры 'трудно для распознавания':
, API C может быть очень эффективным, но будет нуждаться в представленных необработанных данных (т.е. указатели, и т.д.), который не поможет безопасности кода. Используйте существующий API C++ или инкапсулируйте API C с кодом C++.
, например:
// char * d, * s ;
strcpy(d, s) ; // BAD
// std::string d, s ;
d = s ; // GOOD
strtok использования не повторно используем. Что означает, что, если один strtok запускается, в то время как другой не заканчивается, каждый повредит "внутренние данные" другого.
, Как это ясно упрощает более безопасный код, который минимизирует риск загадочных ошибок, который увеличивает пригодность для обслуживания и т.д.?
Используя API C означает использовать необработанные типы, которые могут привести к интересным ошибкам как переполнение буфера (и потенциальное повреждение стека), когда sprintf заходит слишком далеко (или строковая обрезка при использовании snprintf, который является своего рода повреждением данных). Работая над необработанными данными, malloc может легко злоупотребить, как показано следующий код:
int * i = (int *) malloc(25) ; // Now, I BELIEVE I have an array of 25 ints!
int * j = new int[25] ; // Now, I KNOW I have an array of 25 ints!
И т.д. и т.д.
Что касается strtok: C и C++ являются поддерживающими стек языками, которые включают пользователю для не заботы о том, что функции выше его собственного на стеке, и какие функции будут вызваны ниже его собственного на стеке. strtok удаляет эту свободу "не заботы"
Общедоступное наследование должно смоделировать принцип замены Лисков (LSP).
Повторное использование кода / импорт без substituability должно быть реализовано с частным наследованием, когда очень сильная связь имеет смысл, или с агрегированием иначе.
Если используемый набор инструментальных средств (или спроектированное использование) имеет неэффективную реализацию исключения , могло бы быть мудро избежать их использования. Я работал в таких условиях.
Обновление: здесь чужое объяснение для "Встроенного C++", который, кажется, исключает исключения. Это делает следующие моменты:
существует более тщательно продуманный текст на той странице, я не хотел копировать все это. Плюс, этому 10 лет, таким образом, это могло бы быть бесполезно больше, который является, почему я включал часть о наборе инструментальных средств. Возможно, это должно также читать, "если память не считают основной проблемой", и/или, "если предсказуемый ответ в режиме реального времени не требуется", и так далее.
Имена методов и имена переменной в общей схеме именования для непротиворечивости; я не склонен быть беспокойством очень чем-либо еще при чтении источника.
Всегда, всегда, всегда делайте надлежащую инициализацию элемента данных на объектной конструкции.
я столкнулся с проблемой, где конструктор Object полагался на некоторую инициализацию "по умолчанию" для своих элементов данных. Создание кода под двумя платформами (Windows/Linux) дало различные результаты и дефицитную ошибку памяти. Результат состоял в том, что элемент данных не был инициализирован в конструкторе и использовал, прежде чем он был инициализирован. На одной платформе (Linux) компилятор инициализировал его к тому, что программист думал соответствующее значение по умолчанию. В Windows значение было инициализировано к чему-то - но мусор. На использовании элемента данных все вышло из строя. Как только инициализация была зафиксирована - больше проблемы.
Запретите t[i]=i++;
f(i++,i);
, и так далее поскольку нет никаких (портативных) гарантий относительно того, что выполняется сначала.
Принцип наименьшего количества удивления .
, Возможно, это не "разновидность" правил, которые Вы ищете, но я определенно поместил его сначала.
Это не только корень, причина и проверка работоспособности для всего скучного материала как форматирование и комментарий, что инструкции, но - мне, что еще более важно - ставит акцент на коде, считанном и понятом, а не просто скомпилированном.
Это также покрывает единственную разумную качественную меру по коду, с которой я когда-либо встречался - WTF's в минуту .
я использовал бы ту первую точку, чтобы подчеркнуть важность и значение ясного, последовательного кода, и мотивировать следующие объекты в стандарте кодирования.
Не добавляйте типы или функции к глобальному пространству имен.
, структуры являются легальными конструкциями C++, привыкшими к агрегированным данным вместе. Однако, данные должны всегда правильно инициализироваться.
Все структуры C++ должны иметь, по крайней мере, конструктора по умолчанию, который установит его агрегированные данные на значения по умолчанию.
struct MyStruct // BAD
{
int i ; bool j ; char * k ;
}
struct MyStruct // GOOD
{
MyStruct() : i(0), j(true), k(NULL) : {}
int i ; bool j ; char * k ;
}
И если они обычно инициализируются в некотором роде, обеспечьте конструктора, чтобы позволить пользователю избежать инициализации структуры C-стиля:
MyStruct oMyStruct = { 25, true, "Hello" } ; // BAD
MyStruct oMyStruct(25, true, "Hello") ; // GOOD
, Как это ясно упрощает более безопасный код, который минимизирует риск загадочных ошибок, который увеличивает пригодность для обслуживания и т.д.?
структура Наличия без надлежащего конструктора оставляет пользователя этой структуры задачей инициализации его. Так, следующий код будет копией, вставляемой от функции до функции:
void doSomething()
{
MyStruct s = { 25, true, "Hello" } ;
// Etc.
}
void doSomethingElse()
{
MyStruct s = { 25, true, "Hello" } ;
// Etc.
}
// Etc.
, Что означает, что, в C++, если необходимо добавить поле в структуре, или изменяют порядок внутренних данных, необходимо пройти все эти инициализации, чтобы проверить, что каждый все еще корректен. С надлежащим конструктором изменение внутренностей структур разъединяется от его использования.
Используйте инструмент линта - т.е. Линт ПК. Это поймает многие 'структурные' проблемы инструкции по кодированию. Значение вещей, которые читают в фактические ошибки, а не проблемы стиля/удобочитаемости. (Не то, чтобы удобочитаемость не важна, но это - меньше, чем фактические ошибки).
Пример, вместо того, чтобы требовать этого стиля:
if (5 == variable)
Как способ предотвратить 'непреднамеренное присвоение' ошибка, позвольте линту найти его.
Только тривиальное использование?: оператор, т.е.
float x = (y > 3) ? 1.0f : -1.0f;
в порядке, но это не:
float x = foo(2 * ((y > 3) ? a : b) - 1);
Предпочтите стандартно-совместимый код. Предпочтите пользоваться стандартными библиотеками.
Фигурные скобки для любого проверяют утверждение. (Благодаря собственному опыту и укрепленный путем чтения Кода Полный v2):
// bad example - what the writer wrote
if( i < 0 )
printf( "%d\n", i );
++i; // this error is _very_ easy to overlook!
// good example - what the writer meant
if( i < 0 ) {
printf( "%d\n", i );
++i;
}
Запись безопасный и корректный код сначала.
Затем если у Вас есть проблемы производительности, и если Ваш профилировщик сказал Вам, код является медленным, можно попытаться оптимизировать его.
Никогда не полагают, что Вы оптимизируете отрывки кода лучше, чем компилятор.
При поиске оптимизации, изучите алгоритмы используемые, и потенциально лучшие альтернативы.
, Как это ясно упрощает более безопасный код, который минимизирует риск загадочных ошибок, который увеличивает пригодность для обслуживания и т.д.?
Обычно, "оптимизированный" (или предположительно оптимизированный) код намного менее более ясен, и будьте склонны выражаться через сырые данные, почти машина путь, вместо более ориентированного на бизнес пути. Некоторая оптимизация полагается switchs, если, и т.д., и затем будет более трудной протестировать из-за нескольких путей выполнения кода.
И конечно, оптимизация прежде, чем часто представлять вывод для обнуления увеличения производительности.
Примечание стороны: не налагайте SESE ( Однократный Единственный Выход ) (т.е. не запрещайте больше чем один return
, использование break
/ continue
/...)
В C++, это - утопия, как throw
другая точка возврата. SESE имел два преимущества в C и не допускающих исключений языках:
, Как это ясно упрощает более безопасный код, который минимизирует риск загадочных ошибок, который увеличивает пригодность для обслуживания и т.д.?
Не наличие ясной философии владения памяти приводит к интересным ошибкам или утечкам памяти, и время потеряло удивление, если символ * возвращенный этой функцией должен быть освобожден пользователем, или нет, или отдан к специальной функции освобождения и т.д.
как можно больше, функция/объект, выделяющая память, должна быть функцией/объектом, освобождающей его.
утверждают все предположения, включая временные предположения, как нереализованное поведение. утверждайте функциональные условия входа и выхода, если нетривиальный. утверждайте все нетривиальные промежуточные состояния. Ваша программа никогда не должна отказывать без утверждать сбоя сначала. можно настроить Ваш утверждать механизм для игнорирования будущих происшествий.
код обработки ошибок Использования для условий Вы ожидаете происходить; используйте утверждения для условий, которые никогда не должны происходить. Обработка ошибок обычно проверяет на плохие входные данные; утверждения проверяют на ошибки в коде.
, Если код обработки ошибок используется для обращения к аномальному условию, обработка ошибок позволит программе ответить на ошибку корректно. Если утверждение уволено за аномальное условие, корректирующее действие не должно просто обрабатывать ошибку gracefully— корректирующее действие, должен изменить исходный код программы, перекомпилировать и выпустить новую версию программного обеспечения. Хороший способ думать об утверждениях как исполняемый файл documentation—, Вы не можете полагаться на них, чтобы заставить код работать, но они могут зарегистрировать предположения более активно, чем комментарии языка программы могут [1].
Сохраните функции к разумному размеру. Лично, мне нравится сохранять функции под 25 строками. Удобочитаемость улучшена, когда можно принять функцию как единицу вместо того, чтобы иметь необходимость просканировать вверх и вниз по попытке выяснить, как это работает. Если необходимо прокрутить для чтения его, это делает вопросы еще хуже.
Использование станд.:: вектор каждый раз, когда необходимо создать буфер данных, даже если размер фиксируется.
Использование станд.:: строка каждый раз, когда у Вас должна быть строка.
, Как это ясно упрощает более безопасный код, который минимизирует риск загадочных ошибок, который увеличивает пригодность для обслуживания и т.д.?
станд.:: вектор: пользователь вектора может всегда находить его размер, и вектор может быть изменен в случае необходимости. Это может даже быть дано (через (& (myVector[0])) нотация) к API C. Конечно, вектор уберет после себя.
станд.:: строка: Почти те же причины выше. И факт, это будет всегда правильно инициализироваться, что это не может быть превышено, что это обработает модификации корректно, как конкатенации, присваивание, и т.д., и естественным способом (использующий операторы вместо функций)
Удостоверьтесь, что предупреждение Вашего компилятора уровня установлено достаточно высоко (/Стена предпочтительно) так, чтобы это поймало глупые ошибки как:
if (p = 0)
, когда Вы действительно имели в виду
if (p == 0)
так, чтобы Вы не должны были обращаться к еще более глупым приемам как:
if (0 == p)
, которые ухудшают удобочитаемость Вашего кода.
Используйте ссылки вместо указателей, если это возможно. Это предотвращает постоянные защитные ПУСТЫЕ проверки.
использование:
static_cast
const_cast
reinterpret_cast
dynamic_cast
, но никогда броски C-стиля.
, Как это ясно упрощает более безопасный код, который минимизирует риск загадочных ошибок, который увеличивает пригодность для обслуживания, и т.д.
, Каждый бросок ограничил полномочия. Например, если Вы захотите удалить константу (по любой причине), [то 114] не изменит тип одновременно (который мог быть ошибкой, трудной найти).
кроме того, это позволяет рецензенту искать их и затем, кодер для выравнивания по ширине их в случае необходимости.
Используйте const
идентификаторы по умолчанию. Они обеспечивают гарантии читателя/специалиста по обслуживанию и являются путем, легче создавать в, чем вставить впоследствии.
И членские переменные и методы были бы объявлены const
, а также аргументы функции. const
членские переменные осуществляют надлежащее использование списка инициализатора.
побочный эффект А этого правила: избегайте методов с побочными эффектами.
Избегайте использования сгенерированного конструктора копирования и оператора = по умолчанию.
class foo { //... private: foo( const foo& ); const foo& operator=( const foo& ); };
Или более понятным способом , если вы используете ускорение:
class foo : private boost::noncopyable { ... };
Передайте входные аргументы по константной ссылке , а аргументы вывода или ввода-вывода - по указателю. Это правило взято из руководства по стилю Google.
Раньше я испытывал абсолютное отвращение к указателям и предпочитал использовать ссылки, когда это возможно (как было предложено одним из авторов в этом потоке). Однако принятие этого соглашения о выводе аргументов в качестве указателя сделало мои функции более удобочитаемыми. Например,
SolveLinearSystem(left_hand_side, right_hand_side, ¶ms);
проясняет, что записываются параметры.