2010-06-14 1 views
1

Этот парень:VSC++, виртуальный метод при плохом адресе, любопытная ошибка

virtual phTreeClass* GetTreeClass() const { return (phTreeClass*)m_entity_class; } 

При вызове, разбился программа с нарушением доступа, даже после полной перекомпиляции. Все функции-члены и виртуальные функции-члены имели правильные адреса памяти (я наводил курсор мыши на методы в режиме отладки), но у этой функции был неправильный адрес памяти: 0xfffffffc.

Все выглядело нормально: указатель «этот», и все работает нормально, пока эта функция не вызовет вызов. Эта функция также довольно старая, и я не менял ее в течение длительного времени. Проблема сразу же возникла после некоторой работы, и я прокомментировал все, чтобы увидеть, что делает это, без каких-либо успехов.

Так что я удалил виртуальный, скомпилированный, и он отлично работает. Я добавляю виртуальный, скомпилированный, и он все еще отлично работает! Я ничего не изменил и помню, что раньше делал полную перекомпиляцию и все еще имел ошибку.

Я не смог воспроизвести проблему. Но теперь он вернулся. Я ничего не изменил. Удаление виртуальных исправляет проблему.

+4

В качестве краткого комментария вы должны действительно избегать использования приемов C-стиля при работе с иерархиями классов C++, особенно при работе с полиморфными классами. Есть слишком много возможностей для ошибок. –

+1

Я сомневаюсь, что удаление «виртуального» исправлено «ничего». Неопределенное поведение непредсказуемо, возможно, оно даже работает, когда вы меняете что-то невиновное. Вам нужно будет сделать необходимую работу, чтобы воспроизвести это. Вероятно, вы нашли ошибку таким образом. Если нет, у вас есть хороший репродуктивный случай, чтобы показать здесь и попросить другие мнения. – sbi

+2

Нам действительно нужно увидеть больше кода, чем это, чтобы быть полезным. Я имею в виду, откуда приходит m_entity_class? Какой тип? Какие функции влияют на него, и когда они называются, с какими вариантами использования? – Puppy

ответ

2

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

+0

, даже тогда не использовать их, одна из C++-трансляций будет работать и используя это покажет, что вы имеете в виду. – Mark

+0

Спасибо, я все еще работал над тем, чтобы создавать стили C++, и теперь изменил его внутри этих методов. В этом случае я использую только базовое для дочернего литья, потому что я не хочу тратить память на сохранение указателя для каждого дочернего класса. – Xilliah

+0

Ваша ошибка, вероятно, существует, потому что это не дочерний класс. Если у вас есть ребенок *, сохраните его как ребенка *. Если у вас есть база *, не повышайте ее до ребенка *. – Puppy

0

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

Мы иногда впадать в такие необъяснимые проблемы и исправления тоже. Здесь есть миф, который удаляет файл ncb после исправления сборки.

+2

Правда, но обвинение в компиляторе и/или линкере почти всегда оказывается неправильным.:) – Troubadour

+0

На самом деле, более вероятно, что восстановление вызвало ранее не перестроенный файл, чтобы перекомпилировать его, тем самым устраняя проблему. Компилятор, который ведет себя неправильно во все времена, маловероятен, но тот, который работает иногда и не работает, иногда даже менее вероятен. –

+0

Возможно, вы правы. Я просто разочарован в данный момент, потому что я * испытываю положительные проблемы с компоновщиками на данный момент (возможно, сбой/local builds совместимость, не спрашивайте) –

0

Учитывая, что перекомпиляция первоначально исправила проблему, сначала попробуйте выполнить полную очистку и перестроить.

Если это не удается, то очень вероятно, что хотя ваш указатель this окажется вам правильным, он фактически удален/деконструирован и направлен на память мусора, которая просто выглядит как настоящий объект, который был там раньше. Если вы используете gdb для отладки, первым словом у указателя объекта будет vtable. Если вы делаете x/16xw <addr> (например) дамп памяти в этом месте, gdb расскажет вам, какой тип vtable этого объекта находится там. Если это самый родительский тип, то объект определенно ушел.

Альтернативно, если этот указатель одинаковый каждый раз, когда вы можете установить точку останова в деструкторе класса с условием, что this == known_addr.

+0

Спасибо, esp за последний отзыв. Я отключил освобождение памяти, и это все еще происходило. – Xilliah

Смежные вопросы