Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
1 / 1 / 0
Регистрация: 05.12.2024
Сообщений: 60

О корректном завершении программ на с++

01.11.2025, 19:49. Показов 6543. Ответов 77
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток,

Изучая книгу Страуструппа "Язык программирования С++. Специальное издание", обратил внимание на следующее утверждение "При вызове exit() не будут вызваны деструкторы локальных переменных во всех функциях вверх по цепочке имевших место функциональных вызовов. Генерация и перехват исключений гарантируют корректное уничтожение локальных объектов. Вызов же exit() не позволяет корректно отработать всем функциям из цепочки вызовов. Поэтому лучше не ломать контекст вызова функций и просто сгенерировать исключение, а вопрос о том, что делать дальше, оставить обработчикам"

Допустим, в моей программе в месте, далеком по цепочке вызовов от main(), возникло событие, означающее что программа штатно закончило свою работу. Означает ли написанное выше что:
1) не стоит использовать библиотечные фукнции std::exit(), std::abort()
2) можно не заморачиваться с "правильным" завершением всех функций из цепочки вызовов, а достаточно сгенерировать исключение throw finish(), например. Разместить обработчик в main() и предусмотреть в нем вызов деструкторов глобальных объектов?

Хотелось бы понять и запомнить как правильно поступать при необходимости завершения сложных программ, от которых зависят в т.ч. другие процессы. Понятно, что простые учебные программы можно завершать как угодно.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
01.11.2025, 19:49
Ответы с готовыми решениями:

Корректное закрытие программы при завершении работы Windows
Моя программа при старте сворачивается в трей и периодически выполняет определенные операции. Окно...

Корректное завершение работы сокетов
У меня система работает на синхронных сокетах. Для приема данных создается отдельный поток...

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

77
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
04.11.2025, 22:10
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Igor3D Посмотреть сообщение
Тут скользкий момент. С готовыми инструментами для char * в языке совсем не густо, лучше для std::string, хотя по-моему и там бедненько. Многие предпочитают не тратить времени на "допотопный" char *, это имеет свои плюсы/минусы. Лично мне не кажется что написать пяток-десяток хороших ф-ций - такая уж потеря времени, пользы больше.
Похоже кто-то не знает, что весь подобный функционал имеют потоки С++.
Который вероятно лишь обертка над уже готовыми функциями и их как оказалось уже достаточно.
Больше того, обеспечен функционал порционного доступа к данным.

Цитата Сообщение от Royal_X Посмотреть сообщение
Может сейчас уже не такой медленный?
Такой же.
К тому же, был бы смысл сравнивать если бы задача сводилась к нахождению одного паттерна.
А если 10 раз делать match, то регулярка будет как минимум в 10 раз медленней.
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6181 / 2876 / 1042
Регистрация: 01.06.2021
Сообщений: 10,555
04.11.2025, 22:43
Цитата Сообщение от SmallEvil Посмотреть сообщение
Такой же.
Ясно.
0
1968 / 824 / 115
Регистрация: 01.10.2012
Сообщений: 4,862
Записей в блоге: 2
05.11.2025, 03:30
Немного отрихтовал
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
LCType ParseLineComment( const char * s, size_t len, bool & insideFlag )
{
 size_t numIn = 0, numOut = 0;  // counts of commented and not commented fragments 
 
 while (len > 0) {
   
// if we're already in comments then we're interested only in "*/"  (comments end)
  if (insideFlag) {
    const char * end = Find(s, len, "*/");  // the Find is a function such as strnstr
    if (!end) break;
 
    insideFlag = false;
    ++numIn;
    auto num = (end - s) + 2;
    len -= num;
    s += num;     // advance to next
    continue;
  }
 
// looking for both comments start
  const char * lc1 = Find(s, len, "//");  
  const char * lc2 = Find(s, len, "/*");  
 
// check for no any comment start
  if (!lc1 && !lc2) break;
 
// choose the first start
  if (lc1 && lc2)
   if (lc1 < lc2)
    lc2 = nullptr;
   else
    lc1 = nullptr;
 
// single line 
  if (lc1) {
   if (lc1 > s)
     ++numOut;
   ++numIn;
   break;
  }
 
// multiline
  if (lc2 > s)
    ++numOut;
  ++numIn;
  insideFlag = true;
  auto num = lc2 - s + 2;
  len -= num;
  s += num;     // advance to next
 }
 
 if (!countIn)
  return insideFlag ? lc_full : lc_none;
 
 return countOut ? lc_part : lc_full; 
}


Цитата Сообщение от sdf45 Посмотреть сообщение
по-моему std::regex мог бы облегчить страдания
При любом парсинге народ бросается в регулярку. То что она тут явно не подходит никогда никого не смущает. По-человечески понятно: "я же это учил (во всяком случае читал), ну не зря же!". Потом пытаются задействовать великий и могучий дуст. С тем же успехом. Писать сами упорно не хотят, это (позорный) велик, костыль и.т.п. Все должно быть "ис каропки"
0
фрилансер
 Аватар для Алексей1153
6454 / 5655 / 1129
Регистрация: 11.10.2019
Сообщений: 15,054
05.11.2025, 05:56
Royal_X, да, я парсер переделывал даже из-за этого.
Дело в не в парсерах, а в том, что регулярка - это общий случай.

Пабысраму накидать прототип парсера или сделать что-то, не требующее спешки (единоразовый парс логов) - нормально.

А если нужна ловля миллисекунд, то велкам в char* std::string_view
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
05.11.2025, 12:45
Цитата Сообщение от Алексей1153 Посмотреть сообщение
А если нужна ловля миллисекунд,
На этапе проектирования и разработки никто не ловит миллисекунды.
Оптимизация если производится то позже.
А иногда так вообще когда-то-потом или никогда.
Возьмем для примера любой набор компиляторов для одного и того же ЯП.

Преждевременная оптимизация - один из камней преткновения при разработке.
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6181 / 2876 / 1042
Регистрация: 01.06.2021
Сообщений: 10,555
05.11.2025, 12:57
Цитата Сообщение от Алексей1153 Посмотреть сообщение
регулярка - это общий случай
ради справедливости нужно отметить, что говнокод может быть медленнее регулярки...
0
 Аватар для Наталья8
523 / 373 / 66
Регистрация: 09.03.2016
Сообщений: 3,960
05.11.2025, 13:32
Не пользовал я регулярку. Писал на if/else..
Мой гавнокод - быстрый гавнокод...
А где сядешь, раньше выйдешь...

Добавлено через 4 минуты
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// -------------------------------
    while (getline(fin, msg))//читать в массив построчно пока есть строки
        {
    char *cut_ptr = &msg[0];// Проехать до http в строке из текста
    
    if (one || edit_txt_len)
    while (((cut_ptr = strchr(cut_ptr, 'h')) == NULL || *(cut_ptr + 1) != 't' || *(cut_ptr + 3) != 'p' || *(cut_ptr + 6) != '/'))
            {
                if (cut_ptr == NULL ){
//------------------------------- В этой строке нет интернет адреса.
                    cut_ptr = &msg[0]; // Пробежаться по строке и задолбить все слова индентичные слову из edit
        if (edit_txt_len) {
            do {
                if (!strncmp(cut_ptr, edit_txt, edit_txt_len))
                for (int z = 0; z < edit_txt_len; ++z)*(cut_ptr + z) = '*';
                ++cut_ptr;
               } while (*(cut_ptr + edit_txt_len) != '\0');
             }
//-------------------------------       
cut_ptr = &msg[0] + strlen(msg.c_str());// Указатель на нультерминаторе (линка в строке нет)
Сын говорил - ни одной блохы...
Кошка. На ней блохы...
0
1 / 1 / 0
Регистрация: 05.12.2024
Сообщений: 60
05.11.2025, 19:41  [ТС]
Цитата Сообщение от Igor3D Посмотреть сообщение
Теперь со структурированием. Немного помогу, задача не такая уж простая.
Поработал с Вашим каркасом. Взялся за первый вариант и развил его. Переработка позволила поймать редкую ошибку, когда крайняя строка считалась за две (в редких случаях). Есть снижение производительности в релизной версии, буду дальше заниматься и пробовать другие варианты, в т.ч. string_view и поток istringstream. Хочу для себя прочувствовать разные подходы, понять их плюсы и минусы.

Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Находит окончание текущей строки, настраивает указатель исходного текста на следующий за строкой символ.
// Рассчитывает длину строки в символах и записывает это значение в переменную, переданную по указателю
// Возвращает указатель на начальный символ строки. В строку включается завершающий символ
// @param ioSrc     ссылка на указатель на массив с исходным текстом
// @param oLen      длина возвращаемой строки
const char* takeLine(const char*& ioSrc, long long* oLen)
{
  const char* begin = ioSrc;
  const char* eol = strstr(ioSrc, "\n");      
  if (!eol) 
  {
    *oLen = 0;
    while (*ioSrc)
    {
      ++ioSrc;
      ++*oLen;
    }
    return begin;
  }
  *oLen = eol - ioSrc + 1;
  ioSrc = ++eol;
  return begin;
}
 
// определяет содержит ли строка подстроки, открывающие или закрывающие комментарии
// @return  состояние строки: является или нет комментарием, закомментирована частично или полностью 
LCType parseLineComment(const char* s, long long len, bool& insideFlag)
{
  const char* lastChar = s + len - 1;
  LCType mlCommentStatus = lc_none;
  while (len > 0) {
 
    // if we're already inside comments (opened by prev lines)
    // then we're interested only in "*/"  (comments end)
    if (insideFlag) {
      const char* end = strstr(s, "*/");  // the Find is a function such as strnstr
      if (end > lastChar) end = 0;
      if (!end) return lc_full;   // keep current state
 
      insideFlag = false;
      mlCommentStatus = (*(s+1) == '\r' || *(s+1) == '\n') ? lc_full : lc_part ;
      len -= (end - s) + 2;
      s = end + 2;     // advance to next
      continue;
    }
 
    // lookup both comments begin
    const char* lc1 = strstr(s, "//");
    if (lc1 > lastChar) lc1 = 0;    // в MSVC нет функции strnstr, выхожу из положения таким образом
    const char* lc2 = strstr(s, "/*");
    if (lc2 > lastChar) lc2 = 0;
 
    // check for no any comment begin
    if (!lc1 && !lc2)
      return mlCommentStatus;
 
    // choose the first start
    if (lc1 && lc2)
      if (lc1 < lc2)
        lc2 = nullptr;
      else
        lc1 = nullptr;
 
    // single line 
    if (lc1)
      return (lc1 == s) ? lc_full : lc_part;
 
    // multiline
    insideFlag = true;
    mlCommentStatus = (lc2 == s) ? lc_full : lc_part;
    len -= (lc2 - s) + 2;
    s = lc2 + 2;     // advance to next
  }
  return mlCommentStatus;  // сюда попадаем если в конце текста незакрытый комментарий вида "/*"
}                                         
 
// парсер проходит по исходному тексту src, построчно ищет комментарии и подсчитывает их количество
void lexical_analizer::I3D_getInfoFromHeader(HeaderInfo* headerInfo, const char* src)
{
  headerInfo->commented = 0;
  headerInfo->notCommented = 0;
  headerInfo->words = 0;
  long long len = 0;
  bool insideFlag = false;
  while (true)
  {
    const char* s = ::takeLine(src, &len);
    if (!s || !*s) return;
    if (::parseLineComment(s, len, insideFlag) == lc_none)
      headerInfo->notCommented++;
    else
      headerInfo->commented++;
  }
}
0
1968 / 824 / 115
Регистрация: 01.10.2012
Сообщений: 4,862
Записей в блоге: 2
05.11.2025, 22:03
Цитата Сообщение от Алексей1153 Посмотреть сообщение
А если нужна ловля миллисекунд
А если ловля не нужна, то что? Думаю Вы вводите общественность в заблуждение постоянно намекая что, мол, с регуляркой решение очевидно, "в кармане", но вот беда - скорость. Это совсем не так. Учитывая что комментарии могут экранировать друг друга, регулярное выражение может получиться совсем не простым. Наверно поэтому оно здесь и не было предъявлено. Да и строки еще надо как-то подсчитывать. И хорошо ли иметь такое счастье (в смысле поддерживать/сопровождать регулярку) - тоже вопрос.

Цитата Сообщение от Алексей1153 Посмотреть сообщение
то велкам в char* std::string_view
Опять большевистский лозунг: юзайте string_view - и будет вам счастье! И где же оно, это счастье? Теперь мы вместо char можем работать напр с юникодом. Пусть для файлов-исходников это не актуально, но согласен - достижение. Но.. это .. все. Быстрее не будет, даже чуть медленнее. С точки зрения написания кода - затраты практически те же. Ну используем getline вместо самопального TakeLine, сэкономим строк 10. А всю логику комментариев придется писать точно так же.

Вот и весь "современный С++"
0
1 / 1 / 0
Регистрация: 05.12.2024
Сообщений: 60
05.11.2025, 22:46  [ТС]
Цитата Сообщение от Igor3D Посмотреть сообщение
const char * lc1 = Find(s, len, "//");  
  const char * lc2 = Find(s, len, "/*");
Мне пришла идея все построить вокруг этого кода от Igor3D, вообще всё.
Вот что получилось. Имхо симпатично:

Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
void proceedMultiLineComment(lexical_analizer::HeaderInfo* headerInfo, const char*& ioSrc)
{
    while (*ioSrc)
    {
        const char* eol = strstr(ioSrc, "\n");
        const char* elc = strstr(ioSrc, "*/");
        const char* min = eol;
        headerInfo->commented++;
        if (elc && min > elc) min = elc;
        if (!min) return;
        if (min == eol)
        {
            ioSrc = ++eol;
        }
        else
        {
            const char* eol2 = strstr(ioSrc, "\n");
            if (eol2) ioSrc = ++ eol2;
            return;
        }
    }
}
 
void lexical_analizer::advanced_getInfoFromHeader(HeaderInfo* headerInfo, const char* ioSrc)
{
    headerInfo->commented = 0;
    headerInfo->notCommented = 0;
    headerInfo->words = 0;
    while (*ioSrc)
    {
        const char* eol = strstr(ioSrc, "\n");
        const char* slc = strstr(ioSrc, "//");
        const char* mlc = strstr(ioSrc, "/*");
        const char* min = eol;
        if (slc && min > slc) min = slc;
        if (mlc && min > mlc) min = mlc;
        if (!min)
        {
            headerInfo->notCommented++;
            return;
        }
        if (min == eol)
        {
            headerInfo->notCommented++;
            ioSrc = ++eol;
            continue;
        }
        if (min == slc)
        {
            headerInfo->commented++;
            ioSrc = strstr(ioSrc, "\n");
            ++ioSrc;
            continue;
        }
        ioSrc = mlc + 2;
        ::proceedMultiLineComment(headerInfo, ioSrc);
    }
}
0
Покинул чат.
1132 / 727 / 195
Регистрация: 30.03.2021
Сообщений: 2,379
05.11.2025, 23:20
Цитата Сообщение от Igor3D Посмотреть сообщение
Учитывая что комментарии могут экранировать друг друга, регулярное выражение может получиться совсем не простым. Наверно поэтому оно здесь и не было предъявлено. Да и строки еще надо как-то подсчитывать
А есть смысл учитывать вложенность? Имхо все что за "//" или между "/* */" =коммент, и все.
(другое дело если оно окажется внутри строкового литерала к примеру)
Можно простой регуляркой находить позицию при построчном чтении
C++
1
2
3
4
5
6
7
         std::string line = "...";
         std::regex r(R"(//.*)");
         //std::regex r(R"(/\*)");
         //std::regex r(R"(\*/)");
         std::smatch match;        
         if(std::regex_search(line, match, std::regex(r)))
               std::cout << "match: " << match[0] << " at pos: " << match.position();
Но раз эксперты сказали "медленно" - значит медленно. (Я не знал)

Цитата Сообщение от Igor3D Посмотреть сообщение
"современный С++"
Ну есть например не то что бы современный прям, но все же
C++
1
2
3
4
5
6
      auto it = std::adjacent_find(line.begin(), line.end(),
                                         [](const auto &a, const auto &b){
                                             return a=='/' && b=='*';
                                         });            
      if(it != line.end())
          std::cout << std::distance(line.begin(), it);
и много других штук. Думаю, ТСу полезно будет просто знать, что они есть.
1
1968 / 824 / 115
Регистрация: 01.10.2012
Сообщений: 4,862
Записей в блоге: 2
06.11.2025, 01:37
Лучший ответ Сообщение было отмечено ADnD как решение

Решение

Цитата Сообщение от ADnD Посмотреть сообщение
Взялся за первый вариант и развил его.
По мелочам

1. eol - не всегда один символ \n, хотя сейчас почти всегда так. В старых файлах eol может быть \r\n (да, 2 символа) или \r. Использование std::eol не решает проблему, в файлах данные старые

2. включать eol в извлекаемую строку (длину) не следует

3. для поиска одного символа лучше использовать strchr (вместо strstr)

Главное
Цитата Сообщение от ADnD Посмотреть сообщение
mlCommentStatus = (*(s+1) == '\r' || *(s+1) == '\n') ? lc_full : lc_part ;
Это принципиально неверно. В строке может быть сколько угодно комментариев, поэтому задумка на каждой итерации while искать одно (и только одно) открытие/закрытие. Следующие будут отработаны в следующих итерациях while. Поэтому текущий статус (mlCommentStatus) не имеет смысла - это статус итерации, а не всей строки.

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

Добавлено через 1 час 58 минут
Цитата Сообщение от sdf45 Посмотреть сообщение
А есть смысл учитывать вложенность?
Я имел ввиду (примеры)
C++
1
2
// this multi /* is ignored
/* this single // is ignored
Конечно без этого проще, но.. так можно много чего упростить
Цитата Сообщение от sdf45 Посмотреть сообщение
Можно простой регуляркой находить позицию при построчном чтении
Ну это и без регулярки несложно, но не избавляет от разбора что выше (insideFlag и.т.д.)
Цитата Сообщение от ADnD Посмотреть сообщение
Мне пришла идея все построить вокруг этого кода от Igor3D, вообще всё.
Вот что получилось. Имхо симпатично:
Потестируйте с такой строкой
/* test1 */ /* test2 */
А вообще намного лучше чем первая версия - в этой по крайней мере можно разобраться. Если нужен bool (комментарии есть или нет), то все резко упрощается
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
bool LineHasAnyComment( const char * s, size_t len, bool & insideFlag )
{
 bool hasComment = false;
 
 while (len > 0) {
   
// if we're already in comments then we're interested only in "*/"  (comments end)
  if (insideFlag) {
    hasComment = true;
    const char * end = Find(s, len, "*/");  // the Find is a function such as strnstr
    if (!end) break;
 
    insideFlag = false;
    auto num = (end - s) + 2;
    len -= num;
    s += num;     // advance to next
    continue;
  }
 
// looking for both comments start
  const char * lc1 = Find(s, len, "//");  
  const char * lc2 = Find(s, len, "/*");  
 
// check for no any comment start
  if (!lc1 && !lc2) break;
 
// choose the first start
  if (lc1 && lc2)
   if (lc1 < lc2)
    lc2 = nullptr;
   else
    lc1 = nullptr;
 
   hasComment = true;
 
// single line 
  if (lc1) break;
 
// multiline
  insideFlag = true;
  auto num = lc2 - s + 2;
  len -= num;
  s += num;     // advance to next
 }
 
 return hasComment; 
}
Вы напрасно отказываетесь работать построчно, учет конца строки неприятно "налипает"
1
1 / 1 / 0
Регистрация: 05.12.2024
Сообщений: 60
06.11.2025, 11:00  [ТС]
Цитата Сообщение от Igor3D Посмотреть сообщение
В старых файлах eol может быть \r\n (да, 2 символа) или \r.
В моей системе и сейчас так обстоит дело. Строки в заголовочных файлах завершаются именно \r\n. ОС Windows 11, Microsoft Visual Studio Community 2022 (64-разрядная версия) - Current, Версия 17.14.18 (October 2025). Работе текущей версии программы лишний символ '\r' не мешает. Вот если будет только символ '\r', тогда да, программу придется переделывать. Ну или продумывать некий предварительный анализатор, который смотрит статистику использования символов '\r', '\n' и выбирает разделитель строки.

Цитата Сообщение от Igor3D Посмотреть сообщение
Потестируйте с такой строкой
/* test1 */ /* test2 */
Считалось за один комментарий. Внес минимальные правки, стало считать правильно. Пришлось добавить один флаг bool lineCounted, без него строка "/*\r\n" стала считаться за две.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
void proceedMultiLineComment(lexical_analizer::HeaderInfo* headerInfo, const char*& ioSrc)
{
    while (*ioSrc)
    {
        const char* eol = strchr(ioSrc, '\n');
        const char* elc = strstr(ioSrc, "*/");
        const char* min = eol;
        headerInfo->commented++;
        if (elc && min > elc) min = elc;
        if (!min) return;
        if (min == eol)
        {
            ioSrc = ++eol;
        }
        else
        {
            ioSrc = elc + 2;
            return;
        }
    }
}
 
void lexical_analizer::advanced_getInfoFromHeader(HeaderInfo* headerInfo, const char* ioSrc)
{
    headerInfo->commented = 0;
    headerInfo->notCommented = 0;
    headerInfo->words = 0;
    bool lineCounted = false;   
    while (*ioSrc)
    {
        const char* eol = strchr(ioSrc, '\n');
        const char* slc = strstr(ioSrc, "//");
        const char* mlc = strstr(ioSrc, "/*");
        const char* min = eol;
        if (slc && min > slc) min = slc;
        if (mlc && min > mlc) min = mlc;
        if (!min)
        {
            headerInfo->notCommented++;
            return;
        }
        if (min == eol)
        {
            if (!lineCounted)
                headerInfo->notCommented++;
            else
                lineCounted = false;
            ioSrc = ++eol;
            continue;
        }
        if (min == slc)
        {
            headerInfo->commented++;
            ioSrc = strchr(ioSrc, '\n');
            ++ioSrc;
            continue;
        }
        lineCounted = true;
        ioSrc = mlc + 2;
        ::proceedMultiLineComment(headerInfo, ioSrc);
    }



Мне понравилось, как быстро и просто я внес изменения в эту версию программы и она при этом "не сломалась". Для подсчета слов я напишу long long wordsCount(const char* ioSrc, const char* min), где ioSrc - указатель на начало просматриваемого фрагмента, min - указатель на позицию в которой был обнаружен конец строки или комментарий. Добавлю такие вызовы перед if (!min) в обоих функциях.

Построчная обработка в текущей версии присутствует неявно. Указатели slc, mlc, elc можно назвать "точками отсечения", которые делят обрабатываемую строку на части. Количество комментариев определяется подсчетом таких частей. Это позволило уйти от повторных просмотров исходной строки и упростило программу. Проблем с учетом конца строки не наблюдал. В прошлой версии был звиздец с завершающими строками текста, которые заканчивались '\0' без предварительного символа '\n'. Из-за чего пришлось ломать голову и писать такой костыль:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const char* takeLine(const char*& ioSrc, long long* oLen)
{
  const char* begin = ioSrc;
  const char* eol = strstr(ioSrc, "\n");      
// костыль ----------------------------------------------
  if (!eol)                       
  {                                
    *oLen = 0;                
    while (*ioSrc)        
    {
      ++ioSrc;
      ++*oLen;
    }
    return begin;
  }
// ---------------------------------------------------------
  *oLen = eol - ioSrc + 1;
  ioSrc = ++eol;
  return begin;
}

В текущей версии такой проблемы не наблюдал.

С Вашей помощью, я улучшил понимание как сделать более четкую структуру, возьму этот способ построения программы себе на вооружение на будущее. Огромное Вам спасибо! От души!!!
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
06.11.2025, 15:14
Цитата Сообщение от Igor3D Посмотреть сообщение
Вот и весь "современный С++"
Весь современный С++ заключается именно в том, что в нем не ловят блох.
И не пишут +100500 велосипедов изо дня в день.
Скорость разработки, поддержания кода и т.д. куда важней тех самых блох.

Добавлено через 59 секунд
Цитата Сообщение от ADnD Посмотреть сообщение
const char*& ioSrc
А что это такое и для чего?
0
1 / 1 / 0
Регистрация: 05.12.2024
Сообщений: 60
06.11.2025, 20:02  [ТС]
Цитата Сообщение от SmallEvil Посмотреть сообщение
Сообщение от ADnD
const char*& ioSrc
А что это такое и для чего
Ссылка на указатель. Royal_X предложил в своем примере для улучшения структуры программы. Я потестировал и понравилось: работает как указатель на указатель, при этом "внешний" указатель разыменовывается автоматически при применении. У меня была операция (в другом фрагменте), которая при классическом char** требовала запись *++*name. Для char*& работает *++name.

В моем фрагменте нужно для того, чтобы изменение указателя отражалось и в вызывающей процедуре.
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
07.11.2025, 01:09
Цитата Сообщение от ADnD Посмотреть сообщение
В моем фрагменте нужно для того, чтобы изменение указателя отражалось и в вызывающей процедуре.
Ясно. Перейдешь на классы, такое(указатели на ссылки на указатели) почти не понадобится. Хотя и такая экзотика попадается.
0
Неэпический
 Аватар для Croessmah
18146 / 10730 / 2066
Регистрация: 27.09.2012
Сообщений: 27,029
Записей в блоге: 1
07.11.2025, 12:17
Цитата Сообщение от SmallEvil Посмотреть сообщение
указатели на ссылки на указатели
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6181 / 2876 / 1042
Регистрация: 01.06.2021
Сообщений: 10,555
07.11.2025, 12:27
Учитывая, что const char*& ioSrc вызвал такой интерес и что термины выше могут ввести в заблуждение новичков, которые в будущем зайдут в тему, то объясняю:

это ссылка на указатель на const char (т.е. на неизменяемые данные). Обратите внимание, что сам указатель не является константным, а таковыми являются только данные. Т.е. сам указатель можно менять, но вот символы не могут быть изменены через указатель. Ссылка же для того, чтобы изменения указателя сохранились снаружи. Такое часто применяется во всяких парсерах.

Я не всегда объясняю правильными терминами, поэтому, если что, поправьте меня.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
07.11.2025, 12:27
Помогаю со студенческими работами здесь

Корректное завершение работы консольного приложения
Есть консольное приложение на Qt, которое запускает несколько потоков. Фактически в main я создаю...

Корректное освобождение памяти при принудительном завершении потока TThread
У меня в отдельном потоке выполняются некоторые вычисления. В процессе выполнения этой функции...

Потоки и их корректное завершение
Доброго времени суток! Необходима Ваша помочь. Есть поток, организованный так: void...

Корректное завершение
Когда закрываю окно QGraphicsView`а, процесс остается еще запущен и пишет еще что возникла ошибка....

Корректное завершение QCoreApplication
Добрый день! OC: Windows 7 Professional Qt: 5.7.0 Есть приложение QCoreApplication: int...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
78
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru