Виртуальные методы хаос, как я могу найти, что вызывает это? - PullRequest
3 голосов
/ 08 января 2010

У моего коллеги была проблема с некоторым кодом C ++ сегодня. Он отлаживал странное поведение виртуального метода объекта. Всякий раз, когда метод выполнялся (в режиме отладки, Visual Studio 2005), все происходило неправильно, и отладчик не вмешивался в этот метод, но в деструктор объекта! Кроме того, виртуальная таблица объекта, в списке только ее деструктор, других методов нет.

Я не видел такого поведения раньше, и была напечатана ошибка времени выполнения, что-то говорило о регистре ESP. Хотел бы я дать вам правильное сообщение об ошибке, но сейчас я не помню его правильно.

В любом случае, кто-нибудь из вас, ребята, когда-нибудь сталкивался с этим? Что может вызвать такое поведение? Как бы это исправить? Мы много раз пытались перестроить проект, перезапустили IDE, ничего не помогло. Мы также использовали функцию _CrtCheckMemory перед вызовом этого метода, чтобы убедиться, что память была в хорошем состоянии, и она вернула true (что означает, что все в порядке). У меня больше нет идей. А ты?

Ответы [ 5 ]

2 голосов
/ 08 января 2010

Я видел это раньше. Обычно это происходит потому, что я использую класс из файла Release .LIB, пока я нахожусь в режиме отладки. Кто-то, вероятно, видел лучший пример, и я бы дал свой ответ на его ответ.

1 голос
/ 08 января 2010

Так как это в любом случае угадать, вот один из меня:

Ваш стек испорчен, и _CrtCheckMemory не проверяет это. Относительно того, почему стек поврежден:

  • старый добрый переполнение стека
  • Несоответствие соглашения о вызовах, о котором уже упоминалось (я не знаю, как передача обратного вызова в неправильном соглашении о вызовах в функцию WinAPI; с какими статическими или динамическими библиотеками вы связываетесь?)
  • строка типа printf("%d");
1 голос
/ 08 января 2010

Значение ESP не было должным образом сохранено при вызове функции.

Такое поведение обычно указывает на то, что вызывающий код был скомпилирован с определением класса или функции, отличным от кода, который создал конкретный рассматриваемый класс.

Возможно ли, что вместо недавно созданной версии загружается другая версия dll компонента? Это может произойти, если вы копируете вещи как часть шага после сборки или если процесс запускается из другого каталога или изменяет свой путь поиска dll перед выполнением LoadLibrary или его эквивалента.

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

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

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

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

1 голос
/ 08 января 2010

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

1 голос
/ 08 января 2010

Может быть, вы используете приведение в стиле C, где требуется static_cast<>? Это может привести к тому типу ошибки, о котором вы сообщаете, когда задействовано множественное наследование, например ::10000

class Base1 {};
class Base2 {};
class Derived : public Base1, public Base2 {};

Derived *d = new Derived;
Base2* b2_1 = (Base2*)d; // wrong!
Base2* b2_2 = static_cast<Base2*>(d); // correct
assert( b2_1 == b2_2 ); // assertion may fail, because b2_1 != b2_2

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

ИЛИ: Совершенно другая часть вашего кода становится дикой и перезаписывает память. Попробуйте изолировать ошибку и проверить, не возникла ли она. CrtCheckMemory найдет только несколько случаев, когда вы перезаписываете память (например, когда пишете в специально отмеченные места управления кучей).

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