Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Грабли, на которые мы наступаем 
:(
    Опции темы
borisbn
Дата 6.2.2012, 20:44 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Предлагаю собрать здесь ошибки, которые
  •  Проявляются только в рантайме (компайл-тайм неинтересен - такие ошибки находятся и исправляются просто)
  •  Встречаются довольно часто (необязательно у опытных программистов)
  •  Неочевидны как для для неопытных, так и для людей с опытом
Цель: избавить программистов (как опытных, так и не очень) от уймы потерянного времени.
Просьба: постить сюда ошибки, причину ошибки, и, самое главное, как уберечься от их совершения.

Итак.
1)
Код

// объект строка, который возвращается ф-цией functionThatReturnsStdString() "живёт" только в строке (1).
// как только выполнение переходит к строке (2), этого объекта уже нет. И, соответственно, указатель,
// который вернула c_str() будет указывать в никуда.
// При вызове ф-ции functionThatRequiresCharPtr() ей будет отдан невалидный указатель
const char * ptr = obj.functionThatReturnsStdString().c_str(); // (1)
functionThatRequiresCharPtr( ptr ); // (2)


2)
Код

std::list< int > objects;
for ( std::list< int >::iterator it = objects.begin(); it != objects.end(); ++it ) {
    std::list< int >::iterator found = objects.find( obj );
    if ( found != objects.end() ) {
        it = objects.erase( found );
    }
}
// в данном случае it меняется в цикле, а затем ему делается ++it. Нужно так
for ( std::list< int >::iterator it = objects.begin(); it != objects.end(); /* здесь ++it не нужно */ ) {
    std::list< int >::iterator found = objects.find( objToRemove );
    if ( found != objects.end() ) {
        it = objects.erase( found );
    }
    else
        ++it;
}
// а лучше так
std::list< int >::iterator theLast = std::remove ( objects.begin(), objects.end(), objToRemove );


3)
Код

// Не знаю, как у вас, но у меня такая ошибка периодически всплывает:
// я, почему-то, уверен, что resize "пробивает" нулями ВСЕ значения вектора, а не только те, которые добавляются ф-цией resize
void Object::resizeAndReset( int count ) {
    m_vector.resize( count, 0 );
}


Это сообщение отредактировал(а) borisbn - 6.2.2012, 20:46


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
boostcoder
Дата 6.2.2012, 21:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



на первый пример недавно наткнулся. потратил часа 4 на поиски бага. весь моцг себе вынес ### smile 
но самое смешное это то, что код я написал за час!

PM WWW   Вверх
fish9370
Дата 6.2.2012, 21:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 663
Регистрация: 15.4.2007
Где: Москва

Репутация: -1
Всего: 1



функция возвращает список регулярных файлов в директории..

Код

int browse_dir(char **matches, int m_size, char *buff, int b_size, int *start, char *dir, const char *prefix) {
        int n = 0;
        DIR *dirp = opendir(dir);
        struct dirent *dp;
        struct stat file_info;

        char path[PATH_MAX];

        int p_len = strlen(prefix);
        while ((dp = readdir(dirp)) != NULL) {
                snprintf(path, sizeof(path), "%s/%s", dir, dp->d_name);
                lstat(path, &file_info);
                if (S_ISREG(file_info.st_mode) && (!p_len || strncmp(dp->d_name, prefix, p_len) == 0)) {
                        int end = strlen(dp->d_name);
                        matches[n++] = strncpy(buff + (*start), dp->d_name, b_size - (*start));
                        (*start) += end;
                        buff[(*start)++] = ';';
                }
        }

        closedir(dirp);
        return n;
}



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




--------------------
undefined
PM MAIL WWW ICQ   Вверх
feodorv
Дата 6.2.2012, 23:24 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 11
Всего: 45



Цитата(fish9370 @  6.2.2012,  21:35 Найти цитируемый пост)
пожалуйста назовите их..

Честно говоря, тема не об этом... Ошибок много:
Цитата(fish9370 @  6.2.2012,  21:35 Найти цитируемый пост)
buff[(*start)++] = ';';

Не проверяется выход за пределы буфера.

Цитата(fish9370 @  6.2.2012,  21:35 Найти цитируемый пост)
(*start) += end;

при выходе за пределы буфера start будет показывать мимо буфера

Цитата(fish9370 @  6.2.2012,  21:35 Найти цитируемый пост)
matches[n++] = 

Тут тоже нужно вставить проверку, что вы не превысили лимит m_size...

Цитата(fish9370 @  6.2.2012,  21:35 Найти цитируемый пост)
lstat(path, &file_info);

Не проверяется возвращаемое значение, а вдруг файла уже нет... или PATH_MAX не хватило... и в file_info мусор...

Цитата(fish9370 @  6.2.2012,  21:35 Найти цитируемый пост)
int p_len = strlen(prefix);

Раз plen может оказаться нулевой, то было бы неплохо перед strlen проверить prefix на NULL, если, конечно, Вы не пользуетесь исключительно browse_dir( ..., "");

Цитата(fish9370 @  6.2.2012,  21:35 Найти цитируемый пост)
int n = 0;

Если предполагается, что в matches ещё ничего нет, то нужно правильно проинициализировать start: *start = 0;

Цитата(fish9370 @  6.2.2012,  21:35 Найти цитируемый пост)
DIR *dirp = opendir(dir);

dirp не проверяется на NULL...

Ну и можно в конце сделать buff[*start] = '\0', если место ещё оставалось... И конечную ';' (если она есть) поглотить, но я не знаю, как буфер будет использоваться дальше...

Это сообщение отредактировал(а) feodorv - 6.2.2012, 23:49


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
borisbn
Дата 7.2.2012, 08:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(boostcoder @  6.2.2012,  21:14 Найти цитируемый пост)
 потратил часа 4 на поиски бага

Цитата(boostcoder @  6.2.2012,  21:14 Найти цитируемый пост)
код я написал за час

ну дык, стандарт: 20/80. ну, почти smile

Цитата(feodorv @  6.2.2012,  23:24 Найти цитируемый пост)
Честно говоря, тема не об этом...

 smile Честно говоря, вообще не понял, зачем этот код ? Тема то не для того, чтобы искать чужие ошибки, а чтобы показывать часто встречаемые ошибки, на поиск которых уходит куча времени.
По поводу выхода за границы массива - пользуйтесь STL.


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
fish9370
Дата 7.2.2012, 09:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 663
Регистрация: 15.4.2007
Где: Москва

Репутация: -1
Всего: 1



feodorv, спасибо за работу

Цитата(feodorv @  6.2.2012,  23:24 Найти цитируемый пост)
dirp не проверяется на NULL...


да..

Цитата(feodorv @  6.2.2012,  23:24 Найти цитируемый пост)
Не проверяется возвращаемое значение, а вдруг файла уже нет... или PATH_MAX не хватило... и в file_info мусор...


соглашусь, добавим эту проверку

Цитата(feodorv @  6.2.2012,  23:24 Найти цитируемый пост)

Раз plen может оказаться нулевой, то было бы неплохо перед strlen проверить prefix на NULL, если, конечно, Вы не пользуетесь исключительно browse_dir( ..., "");


нет, исключительно не пользуюсь, но вызывающая сторона гарантирует, что префикс не равен NULL, хотя, я Вас услышал..

Цитата(feodorv @  6.2.2012,  23:24 Найти цитируемый пост)
Тут тоже нужно вставить проверку, что вы не превысили лимит m_size...


возможно индексное переполнение - это была первая грубая ошибка..


Цитата(feodorv @  6.2.2012,  23:24 Найти цитируемый пост)
Не проверяется выход за пределы буфера.


Цитата(feodorv @  6.2.2012,  23:24 Найти цитируемый пост)
при выходе за пределы буфера start будет показывать мимо буфера


возможно переполнение - это вторая грубая ошибка 


Цитата(feodorv @  6.2.2012,  23:24 Найти цитируемый пост)
Если предполагается, что в matches ещё ничего нет, то нужно правильно проинициализировать start: *start = 0;


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


Цитата(feodorv @  6.2.2012,  23:24 Найти цитируемый пост)
И конечную ';' (если она есть) поглотить, но я не знаю, как буфер будет использоваться дальше...


это не требуется..

Добавлено @ 10:04
Цитата(borisbn @  7.2.2012,  08:28 Найти цитируемый пост)
По поводу выхода за границы массива - пользуйтесь STL.


извините, забыл напомнить, я пишу исключительно на Си (не считая скриптовых языков)


Цитата(borisbn @  7.2.2012,  08:28 Найти цитируемый пост)
Честно говоря, вообще не понял, зачем этот код


затем, что я собираюсь привезти правильный вариант, а тот код абсолютно рабочий, за исключением тех ньюансов, которые упаминул feodorv
- ошибки на этапе исполнения, при особых обстоятельствах, самые опасные ошибки..

Это сообщение отредактировал(а) fish9370 - 7.2.2012, 11:28


--------------------
undefined
PM MAIL WWW ICQ   Вверх
boostcoder
Дата 7.2.2012, 10:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



borisbn, попроси модераторов чтоб удалили все начиная с третьего поста.

fish9370, буду знать, какой код ты пишешь ;)

Добавлено через 30 секунд
или со второго) он тоже оффтоп.
PM WWW   Вверх
newbee
Дата 7.2.2012, 11:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бревно
**


Профиль
Группа: Участник
Сообщений: 703
Регистрация: 24.8.2011

Репутация: 4
Всего: 19



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

Вот тут на форуме один чувак... volatile или как-то так... просто прется, что С++ остается все таким же "простым" и делает именно то, что требует от него программист. С моей точки зрения, для языка, позиционирующего себя как высокоуровневый, с настолько переусложненным синтаксисом, продолжать оставаться надстройкой над ассемблером недопустимо. В стандартной библиотеке языка все пучком... Конечно в ней очень многого не хватает, но в целом хотя бы ее дизайн очень хорош. Но в core language писать и не удивляться на неочевидности невозможно!
  • Идиотская политика неявного приведения типов, когда по ошибке в foo(bool) передаешь "хеллоу", а компилятор ест и не краснеет. Это допустимо в операторах и функциях сравнения, но не где попало!
  • Совершенно дурацкий механизм опредления пользовательских операторов преобразования типов.
  • Кривая идеология конструирования объектов, когда конструктов вызывается где-то посреди процесса собирания нового объекта.
  • Норкоманское множественное наследование с эпичным костылем в виде виртуального наследования.
  • Кастрированные лямбда-функции.
  • Сказочные танцы с указателями на члены классов, особую пикантность придает уже упомянутое выше виртуальное наследование.
  • Чрезвычайно переусложненный механизм метапрограммирования, и сразу на двух языках: сишный #define и темплейты. Хотя конечно плюсисты слишком задрали нос, называя темплейты метапрограммирванием.
На эти грабли я наступила примерно за неделю писания на С++! Не уверена, что это все прелести языка, но пока в голову больше ничего не приходит...

Это сообщение отредактировал(а) newbee - 7.2.2012, 11:15


--------------------
You're face to face
With man who sold the world
PM   Вверх
borisbn
Дата 7.2.2012, 11:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(boostcoder @  7.2.2012,  10:48 Найти цитируемый пост)
 попроси модераторов чтоб удалили все начиная с третьего поста.

done. кроме сообщ. newbee


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
newbee
Дата 7.2.2012, 12:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бревно
**


Профиль
Группа: Участник
Сообщений: 703
Регистрация: 24.8.2011

Репутация: 4
Всего: 19



Цитата(boostcoder @  7.2.2012,  13:09 Найти цитируемый пост)
минусовщина стразу трем пользователям
Это я начала) Слушала одноименную с минусом песню ленинграда, читала тему и как-то не удержалась (

Цитата(boostcoder @  7.2.2012,  13:09 Найти цитируемый пост)
на лицо психическая неуравновешенность ;) 
Напротив, поциент демонстрирует способность к социальной адаптации. Код читается так: если в теме встречается юзернейм "бусткодер", я затыкаюсь и ухожу.

smile


--------------------
You're face to face
With man who sold the world
PM   Вверх
Static
Дата 7.2.2012, 12:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 185
Регистрация: 6.11.2008

Репутация: 1
Всего: 2



эээ, народ... спокойно!

мое любимое:
Код

if ( getSomething() );
    doSomething();

// или

while ( doSomething() );
    doSomethingElse(); // но это слишком легко обнаружить


Еще, когда только начинал работать, - отлично прошелся по конструкторам копирования. Точнее, по их отсутствию)

Еще хорошо стреляет неправильно написанная проверка выхода из рекурсии. Которая спокойно работает пару месяцев, а потом начинает крашиться. Исключительно в релизе, например.

Еще вот такое
Код

void initSomethingImportant()
{
    assert( init_very_important_lib() && "init library fail" );
    
    important_lib::start( "some_params" );
}

В релизе, естественно, падает =)

Сейчас еще, может, чего-нибудь вспомню.

--------------------
Я не настолько безнадежен, как кажется...
PM MAIL   Вверх
boostcoder
Дата 7.2.2012, 12:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



Цитата(newbee @  7.2.2012,  12:18 Найти цитируемый пост)
поциент

полагаю, намек на происхождение от слова Поц ;)

Добавлено через 4 минуты и 1 секунду
newbee, про виртуальную хрень и наследование ты же в курсе: используй функциональный стиль. С++ при этом становится как Си_на_стеройдах!
PM WWW   Вверх
borisbn
Дата 7.2.2012, 12:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(newbee @  7.2.2012,  11:00 Найти цитируемый пост)
Кривая идеология конструирования объектов, когда конструктов вызывается где-то посреди процесса собирания нового объекта.

про остальное, вроде, понял, а это - никак не пойму. чойта ?


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
newbee
Дата 7.2.2012, 12:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бревно
**


Профиль
Группа: Участник
Сообщений: 703
Регистрация: 24.8.2011

Репутация: 4
Всего: 19



Цитата(borisbn @  7.2.2012,  13:47 Найти цитируемый пост)
про остальное, вроде, понял, а это - никак не пойму. чойта ? 
Вызови из конструктора виртуальный метод например.

Цитата(boostcoder @  7.2.2012,  13:38 Найти цитируемый пост)
используй функциональный стиль
ФП не панацея, в С++ ФП неудобен. /*Смотрела недавно бустовский феникс, не знала плакать или смеяться*/



--------------------
You're face to face
With man who sold the world
PM   Вверх
borisbn
Дата 7.2.2012, 13:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 22
Всего: 135



Цитата(newbee @  7.2.2012,  12:54 Найти цитируемый пост)
Вызови из конструктора виртуальный метод например.

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


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1079 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.