Функция вызывается дважды из одного и того же потока для одного и того же объекта с одним и тем же стеком вызовов - PullRequest
2 голосов
/ 08 мая 2019

Фон

Я отлаживаю один проект с открытым исходным кодом, к которому я хочу присоединиться и выучить C ++.Затем я попытался расширить некоторые функциональные возможности, необходимые для решения одной из проблем, и наткнулся на интересный случай (никогда в жизни не встречал ничего подобного).

Исходный код

QuestSet Player::GetQuestForEvent(uint16 eventId) const
{
    QuestSet eventQuests; // QuestSet is typedef for std::set<uint32>

    for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i)
    {
        uint32 questId = GetQuestSlotQuestId(i);
        if (questId == 0)
            continue;

        QuestStatusMap::const_iterator qs_itr = m_QuestStatus.find(questId);
        if (qs_itr == m_QuestStatus.end())
            continue;

        QuestStatusData const& qs = qs_itr->second;

        Quest const* qinfo = sObjectMgr->GetQuestTemplate(questId);
        if (!qinfo)
            continue;

        if (qinfo->GetEventIdForQuest() == eventId)
            eventQuests.insert(questId);
    }

    return eventQuests; <--- breakpoint here
}

Я заметилчто мой сервер аварийно завершает работу с

необработанное исключение в 0x00007FFE1BE6A388 (KernelBase.dll) в worldserver.exe: 0xC0000005: нарушение прав доступа.

, за которым следует этот журнал с моего сервера

C: \ Program Files (x86) \ Microsoft Visual Studio \ 2019 \ Community \ VC \ Tools \ MSVC \ 14.20.27508 \ include \ xtree (240): Ошибка подтверждения: сопоставить / установить итераторы вдиапазон из разных контейнеров

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

Снимки экрана

  • попадание первой точки останова first breakpoint hit

  • второе попадание в точку останова (окно уведомлений о событиях из окна диагностических инструментов) second breakpoint hit

Это единственное место в проекте, где вызывается эта функция.

void OnLogin(Player* player, bool /*firstLogin*/) override
{
    QuestSet eventQuests = player->GetQuestForEvent(1);
    /*std::for_each(eventQuests.begin(), eventQuests.end(), [&player](uint32 questId)
    {
        player->AbandonQuest(questId);
    });*/
}

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

Устранение неполадок:

  • проект построен в конфигурации отладки
  • callstack, thread и this objectвсе одинаковые в обоих хитах.

1 Ответ

2 голосов
/ 08 мая 2019

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

Visual Studio позволяет вам проверять ассемблерный код возле вашей точки останова, по умолчанию Ctrl+Alt+D Я полагаю. Там вы увидите сочетание инструкций по сборке (что на самом деле делает ваш ЦП) и отладочной информации о том, «из какой строки кода были получены следующие инструкции».

Я ожидаю, что вы увидите, что строка return eventQuests; связана с двумя блоками инструкций по сборке, с другим блоком инструкций между ними. Сначала вы достигнете точки останова в первой группе инструкций, затем будет выполнена вторая группа (например, связанная с циклом или закрывающей скобкой), а затем точка останова будет достигнута еще раз из-за второй группы. Да, это звучит довольно глупо, но отладочная информация, которую выводит MSVC, не самая лучшая, какую я видел.

Еще один простой способ проверить это - вставить оператор печати (например, std::cout << "Hi" << std::endl) перед возвратом и проверить, получаете ли вы одну или две распечатки. Если вы не получите две распечатки, ваш вывод о фактическом входе в функцию более одного раза неверен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...