Ответ 1
Использование исходных указателей и ресурсов вместо объектов RAII.
Недавно обсуждение закончилось смехом над вредными привычками программистов, которые слишком подвержены языку, когда они начинают программировать на другом языке. Лучшим примером может быть программист Pascal, начинающий с #define begin {
и #define end }
при запуске записи C.
Цель состоит в попытке поймать вредные привычки программистов C, когда они начинают использовать С++.
Расскажите о большом, что вы не встречали. Одно из предложений ответа, пожалуйста, попытаться достичь своего рода лучшего.
Для тех, кто заинтересован в хороших привычках, посмотрите на принятый ответ на этот question.
Использование исходных указателей и ресурсов вместо объектов RAII.
Объявление всех переменных в верхней части функции, а не как можно ближе к тому, где они используются.
Не использовать STL, особенно std::string,
и/или
используя std:: strings и возвращаясь к старым функциям string в строгих углах.
используя указатели вместо ссылок
Добавление using
в заголовочные файлы, чтобы они могли избегать имен типа std::string
в объявлениях типов.
Очень опытные разработчики, не понимающие кастинг или даже объектно-ориентированное программирование:
Я начал помогать проекту, и у одного из старших ребят возникла проблема с некоторым кодом, который работал, а теперь нет.
(Названия классов были изменены для защиты невинных, и я не могу вспомнить точные имена) У него был код на С++, который слушал входящие классы сообщений и читал их. Способ, которым он работал в прошлом, состоял в том, что был принят класс Message, и он будет взаимодействовать с переменной на нем, чтобы узнать, какой тип сообщения он был. Затем он C-стиль передал сообщение как другой специализированный класс, который он написал, унаследованный от Message. У этого нового класса были функции, которые извлекали данные, как он этого хотел. Теперь это работало для него прекрасно, но теперь этого не было.
После многих часов, просматривающих его код, он не мог видеть проблему, и я посмотрел через его плечо. Сразу же я сказал ему, что это не очень хорошая идея для C-стиля приведения Message к производному классу, которого это не так. Он не согласился со мной и сказал, что он делал это в течение многих лет, и если это было неправильно, все, что он делает, ошибочно, потому что он часто использует этот подход. Он был подкреплен подрядчиком, который сказал мне, что я ошибался. Они оба утверждали, что это всегда работает, и код не изменился, поэтому не этот подход, а что-то еще, что нарушило его код.
Я посмотрел немного дальше и нашел разницу. Последняя версия класса Message имела виртуальную функцию и ранее не использовала виртуальную. Я сказал им пару, что теперь есть виртуальный стол, и функции просматриваются и т.д. И т.д., И это вызывало их проблемы и т.д. И т.д. В конце концов они согласились, и мне было представлено комментарий, который я никогда не забуду: "Virtual полностью замалчивает полиморфизм и объектно-ориентированное программирование".
Я отправил им копию шаблона декоратора в качестве примера того, как добавить функцию в существующий класс, но ничего не услышал от них. Как они исправили идею, о которой я понятия не имею.
Одно слово: макросы. Я не говорю, что макросам вообще нет места в С++, но бывшие программисты C имеют тенденцию использовать их слишком много после того, как они переключаются на С++.
Использование стилей в стиле C.
С++ позволяет вам самостоятельно выбирать, разрешать ли переводы между несвязанными типами и разрешать ли изменения в квалификаторах const
и volatile
, что значительно улучшает безопасность типа компиляции по сравнению с C. Оно также предлагает абсолютно безопасные забрасывает стоимость проверки времени выполнения.
Отличия в стиле C, неконтролируемые преобразования между любыми типами, позволяют целые классы ошибок, которые можно легко идентифицировать с помощью более ограничительных отбросов. Их синтаксис также очень затрудняет их поиск, если вы хотите проверить багги-код для сомнительных преобразований.
Предполагая, что упомянутые программисты уже сделали ошибку, пытаясь изучить С++:
Написание using namespace std
, потому что каждый делает, а затем никогда не размышляет над его значением.
Или зная, что это значит, но говоря "std::cout << "Hello World" << std::endl;
выглядит уродливым".
Передача объектов с указателями вместо ссылок. Да, еще есть моменты, когда вам нужны указатели на С++, но ссылки более безопасны, поэтому вы должны использовать их, когда сможете.
Сделать все в классе общедоступным. Таким образом, члены данных, которые должны быть частными, не являются.
Не полностью понимает семантику указателей и ссылок и когда использовать тот или иной. Связанным с указателями также является проблема неправильного управления динамически распределенной памятью или сбоя при использовании "умных" конструкций для этого (например, интеллектуальных указателей).
Мой любимый программист С, который пишет один метод с несколькими необязательными аргументами.
В принципе, функция будет делать разные вещи в зависимости от значений и/или допустимости аргументов.
Не использовать шаблоны при создании алгоритмов и структур данных (пример). Это делает вещи слишком локализованными или слишком общими.
т.е. письмо
void qsort(MyStruct *begin, size_t length); //too localized
void qsort(void *begin, size_t length,
size_t rec_size, int(compare*)(void*,void*)); //too generic
вместо
template <class RA_Iter>
void qsort(RA_Iter begin, size_t length);
//uses RA_Iter::value_type::operator< for comparison
Ну, плохой дизайн программы превосходит языки (отливки, игнорирование предупреждений, ненужная маска прекомпилятора, ненужное разворачивание бит, не использование макросов классификации char), а сам язык C не создает слишком много "вредных привычек", (Хорошо, Макросы, esp из каменного века), и многие из идиом переводят напрямую. Но некоторые из них можно было бы рассмотреть:
Использование функции только потому, что она в С++ и поэтому поэтому она должна быть правильным способом сделать что-то. Некоторым программам просто не нужно Наследование, MI, исключения, RTTI, шаблоны (замечательные, поскольку они... отладочная загрузка крутая) или материал виртуального класса.
Придерживаясь фрагмента кода из C, не думая, имеет ли С++ лучший способ. (Есть причина, по которой у вас теперь есть класс, частный, public, const (расширенный за пределами C89), статические классные функции, ссылки.
Не знакомы с С++ i/o lib (его BIG, и вам нужно это знать), и смешивая С++ i/o и C i/o.
Он думает, что С++ - это просто немного другой язык от C. Он продолжит программирование C, замаскированное С++. Нет расширенного использования классов, структуры считаются менее мощными, чем классы, пространство имен, новые заголовки, шаблоны, ничего из этих новых элементов не используется. Он будет продолжать объявлять целые вары без int, он не будет предоставлять прототипы функций. Он будет использовать malloc и бесплатные, небезопасные указатели и препроцессор для определения встроенных функций. Это всего лишь небольшой список;)
Конфуризованное использование структур для классов, чрезмерное использование глобальных методов, которые принимают указатели объектов в качестве аргументов, и глобально доступные экземпляры указателей, a la:
extern Application* g_pApp;
void RunApplication(Application* app, int flags);
Также (не говоря это абсолютно бесполезно, но все же):
const void* buf;
Объявление всех переменных в начале самой функции, даже если переменная будет использоваться только после 100 строк или около того.
Бывает особенно для локальных переменных, объявленных внутри функции.
Не оставлять достаточно хорошо один и использовать C вместо.
Решение проблемы вместо создания монстра, основанного на классе, гарантировало вам медицинскую страховку и преимущества 401K.
Реализация lisp в одном файле и выполнение в нем этого.
Написание нормальных читаемых функций вместо переопределения операторов?
Запись в стиле, который может быть понят младшими программистами, которые считают, что хорошая практика "не написана на С++".
Говоря с ОС на своем родном языке.