Как стать автором
Обновить

Комментарии 50

Неоднократно встречался с подобной ошибкой и на своей шкуре почувствовал все раздражение, когда ошибка после нескольких часов поиска все-таки найдена.

Мне кажется интересна была бы идея самого отслеживания Copy/Paste на уровне среды. Включаем настройку компилятора и нам высвечиваются места, где было совершено копирования строки или нескольких строк кода, с подсветкой изменений сделанных во вставленной строке.
Хм, отличная идея. надо будет поискать в интернетах, или самому сесть разбираться с плагинами к эклипсу.
В IDEA есть.
Спасибо, ещё одна причина посмотреть его на выходных, а то всё руки не доходили.
А где, если не секрет? Сколько работаю, не видел такой функции.
Заменять x на y и на z частенько приходится в вычислительной физике. Это наверное самая частая ошибка. Самое обидное, что понять, где баг, хотя бы примерно — довольно сложно. Видишь баг на графике или картинке — какой-то шум например, а где его в коде искать непонятно.

Очень бы хотел такую тулзу прикрутьить в линуксовой консольке к моей задаче. Такое возможно? Желательно с поддержкой С++0x.
>Заменять x на y и на z частенько приходится в вычислительной физике.

как я вас понимаю. Писал на дипломе код для операций с матрицами 3х3, причем каждый элемент содержал 2 числа. Многие методы процентов на 80 состояли из такого копипаста, где менялись только индексы элементов.
Сам за собой замечал частенько такие «опечатки», поэтому стараюсь не копипастить без нужды. Одна строчка кода написаного с нуля за десяток-другой секунд может сэкономить десятки минут отладки и поиска неисправности.
Стоимость у Вашего продукта, конечно, не детская, но для больших проектов, думаю, такая цена вполне оправдана.
Предлагаю посмотреть на наш новый инструмент — CppCat. Это облегчённый статический анализатор кода для Visual C++. $250 за лицензию.
Когда я был маленький junior, нам ведущие программисты наши нежные пальчики «отсушивали прикладами», когда видели еще на этапе правки кода, что мы пытаемся фрагмент скопипастить. Ну, в смысле, это было грубой ошибкой, влияющей на твои позиции в компании. Вполне успешно, кстати.
Часть таких проблем таки решается выделением общих участков в маленькую вспомогательную функцию.
Просто лениться не надо…

Ну а часть действительно нет…
Поворчу: Вы сделали багрепорты в проекты, указанные в Ваших примерах?
И зачем все ссылки через ваш сайт?
2) И зачем все ссылки через ваш сайт?

Мы заботимся о своих читателя и отслеживаем перемещение статей, ресурсов и так далее.
Читать подробнее здесь — habrahabr.ru/company/intel/blog/101957/
Спасибо за ответы!
Мне думается, в ряде случаев ошибок можно было бы избежать вместе с копированием, применив другой подход:
— если вызывается два раза подряд функция — сделать этот вызов в цикле
— если копируется кусок куда, слишком небольшой, чтобы его выносить в отдельную функцию — всё же выделить в функцию.

Также помогает соображение, что повторяющийся (скопированный) код вообще выглядит подозрительным.
В топике имеются в виду как раз те ситуации, когда выделение однотипного кода в функции нелогично и неприемлимо из-за чрезмерной сложности полученного кода.
Пример:
GetMenu()->CheckMenuItem(IDC_ LINES_X, MF_BYCOMMAND | nState);
GetMenu()->CheckMenuItem(IDC_ LINES_Y, MF_BYCOMMAND | nState);
Можно выпендриться и запихнуть в функцию, но это будет уже мозгодробление.

Другое вопрос — имеет ли такой код вообще право на существование?
В таком случае лучше задуматься об архитектуре проекта в целом и понять причины появления однотипного повторяющегося кода.
Вынос в функцию не спасет!

MyCheck(IDC_ LINES_X);
MyCheck(IDC_ LINES_Y);

Также легко «скопипастить».
Конечно, но ошибку заметить гораздо проще. Чем меньше повторяющегося кода в строчках, тем легче его прочитать.
Foreach не так уж и сложен будет.

foreach (item; [IDC_LINES_X, IDC_LINES_Y]) {
    GetMenu().CheckMenuItem(item, MF_BYCOMMAND | nState);
}

// D
лишний вызов функции (читай: смена окружения) садит производительность
это может быть критичным
Принудительный inline?
… и прочие хитрости белого человека: кто-то задумается, а кто-то — нет
А может, к примеру, сократить размер используемой приложением памяти и выиграть на уменьшении свопа. На этапе написания кода это может определить только телепат.
Make it run, make it correct, make it fast, и только в таком порядке.
Знаете что Кнут называл корнем всех бед? То-то же.
НЛО прилетело и опубликовало эту надпись здесь
Один из способов снизить вероятность такого рода ошибок: Code review.
Да заодно и те только такого рода…
При чём сразу после copy-paste. Откопировали, потом пробежали глазами от начала до конца. Что по исходному варианту, что по копии.
НЛО прилетело и опубликовало эту надпись здесь
> Нельзя запретить программистам копировать код. Это уже маразм.
--Маразм — это старческое заболевание, сопровождающееся потерей памяти. Но если молодой здоровый начальник запретит копировать код, то где здесь маразм? Не понимайт.
написана переменная, какая нибудь activeRecordValue, а ну-ка запретите мне или опишите как будет выглядеть запрет начальником, чтоб я её набирал заново, а не скопировал? глупость же. А может вам и печенье не слабо от самого себя в комате спрятать?
страшно жить с такой ограниченной клавиатурой!
Ctrl+Ins, Shift+Del, Shift+Ins!
y, d, p
НЛО прилетело и опубликовало эту надпись здесь
Cmd+C, Cmd+V!
вообще есть ctrl-ins shift-ins я как то к ним больше привык… :)
Идея форматирования кода хороша, и я её поддерживаю, но она идёт вразрез с автоформаттерами IDE, у которых часто своё представление о том, как выровнять строки и где сделать перенос строки. Не использовать их совсем тоже плохо, особенно новичкам в компании, если они привыкли к другому стилю кодирования. В компании может быть сделан шаблон автоформатирования, который соответствует внутренним требованиям. Кое-где он даже автоматически применяется при коммите кода ко всем файлам. С одной стороны можно не греть голову, правильно расставляя пробелы и скобки, но с другой стороны любой сотрудник может одной волшебной кнопкой испортить тщательную ручную расстановку переносов строк и пробелов в совсем другом фрагменте кода. Этого даже никто не заметит: код компилируется, тесты проходят.

В связи с этим возник вопрос: можно ли в популярных IDE пометить фрагмент кода, как не требующий автоформатирования? Или, скажем, разрешить автоформаттеру для фрагмента править отступы, но запретить править переносы строк?
хм, а в чем тут ошибка?
void DXUTUpdateD3D10DeviceStats(...)
{

else if( DeviceType == D3D10_DRIVER_TYPE_SOFTWARE )
wcscpy_s( pstrDeviceStats, 256, L«WARP» );
else if( DeviceType == D3D10_DRIVER_TYPE_HARDWARE )
wcscpy_s( pstrDeviceStats, 256, L«HARDWARE» );

}
L«HARDWARE» — символы такого рода в списке параметров не будут интерпретированы как нечто иное?
А ЭТО ЕЩЕ ОДИН ПРИМЕР ОШИБКИ ПРИ COPY-PASTE! :))
Я не то скопировал при написании статьи. Вот правильный фрагмент:

else if( DeviceType == D3D10_DRIVER_TYPE_SOFTWARE )
wcscpy_s( pstrDeviceStats, 256, L«WARP» );
else if( DeviceType == D3D10_DRIVER_TYPE_HARDWARE )
wcscpy_s( pstrDeviceStats, 256, L«HARDWARE» );
else if( DeviceType == D3D10_DRIVER_TYPE_SOFTWARE )
wcscpy_s( pstrDeviceStats, 256, L«SOFTWARE» );

Два раза повторяется «DeviceType == D3D10_DRIVER_TYPE_SOFTWARE».
Столкнулся с проблемой копипаста при составлении простенького параметризатора для управления роботом — там 18 параметров, ко всем применяется одна и та же функция. Ошибку искал неделю в уже скомпилированной и поставленной на место работы программе. В конце концов плюнул, и вышел из положения, перегрузив функцию, которая устанавливала параметры, так, чтобы она обращалась не к одной переменной, а к специальной вспомогательной структуре — списку передаваемых параметров с некоторой «обвязкой». Такой подход немного позже привел меня (тогда еще зеленущего студента) к идейке пакетирования команд, так что проблема оказалась полезной.
Copy-Paste это уже технология. О как!
Паттерн. Пора вводить интерфейсы ICopyPaste, ICopyPasteFragment, ICopyPasteContext и так далее, и писать реализацию. Копипастом, конечно же
НЛО прилетело и опубликовало эту надпись здесь
Когда я делаю копипаст, то больше концентрируюсь на этом участке кода и проверяю несколько раз, что все правильно.
А я использую такую тактику: работаю на куском кода, потом отвлекаюсь от него (сознательно, чтобы думать о другом), потом возвращаюсь к нему, и «свежим» взглядом вижу проблемы. Часто приходит мысль: «Ёлки-палки, как же я сразу не заметил такой глупой ошибки!»
Возможно оффтопик: именно за способность уйти от любого дублирования кода и любят языки семейства Lisp.
При этом здесь нет смысла говорить о дублировании кода. Как не думай, проще здесь написать невозможно. Подобных примеров можно привести огромное количество, взяв любую программу. Не нравится, что здесь пример касается GUI, так и в других задачах мы встретим аналогичное:
int texlump1 = Wads.CheckNumForName («TEXTURE1», ns_global, wadnum);
int texlump2 = Wads.CheckNumForName («TEXTURE2», ns_global, wadnum);

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

 char * textures[2] = { 
     "TEXTURE1",
     "TEXTURE2" 
};
int texlump[2] = Wads.CheckNumForName(textures, ns_global, wadnum);

Да, и тут есть копипаст, но на мой взгляд выглядит намного лучше: проще рефакторить, проще увидеть ошибку. Да и красивее в конце концов :)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий