Проблема вызова функции, когда она находится в .lib - PullRequest
3 голосов
/ 07 марта 2009

У меня есть класс со статическим методом, который выглядит примерно так:

class X {
    static float getFloat(MyBase& obj) {
        return obj.value();  // MyBase::value() is virtual
    }
};

Я вызываю его с экземпляром MyDerived, который подклассы MyBase:

MyDerived d;
float f = X::getFloat(d);

Если я свяжу файл obj, содержащий X, с моим исполняемым файлом, все будет работать как положено. Если я ожидаю получить 3.14, я получу его.

Если я создаю .lib, который содержит файл X.obj и ссылку в .lib, он ломается. Когда я вызываю getFloat (), он возвращает -1. # IND00 . Это какой-то тип дозорного значения, который должен сказать мне, что здесь не так?

Что-то отличается, когда вы ссылаетесь в lib, а не в obj напрямую?

Я не получаю никаких предупреждений или ошибок компилятора.

Edit:
Я использую Visual Studio 2005 на Windows XP Pro SP3. Чтобы убедиться, что я не связывал старые файлы, я клонировал метод value () в новый метод value2 () и вызвал его вместо этого. Поведение было таким же.

Редактировать # 2:
Итак, если я отследил вызов с помощью моего отладчика, я обнаружил, что он вообще не входит в мой метод value (). Вместо этого это входит в другой (не связанный) метод. Это заставляет меня думать, что мой vtable поврежден. Я думаю, что поведение, которое я вижу, должно быть побочным эффектом какой-то другой проблемы.


Решено! (спасибо Владу)
Оказывается, я нарушал одно определение правила (ODR), хотя это не было видно из кода, который я разместил. Эта - отличная статья парней из Visual C ++, которая объясняет проблему и один из способов ее устранения. Флаг компилятора / d1reportSingleClassLayout является фантастическим инструментом обучения.

Когда я выбросил макет моего класса для MyBase и MyDerived в двух разных проектах, я обнаружил различия между кодом вызова и кодом библиотеки. Оказывается, у меня в заголовочных файлах было несколько блоков # ifdef , а соответствующий оператор # define был в предварительно скомпилированном заголовке для основного проекта, но не в подпроекте (библиотеке). Я уже упоминал, насколько злыми я считаю макросы препроцессора?

В любом случае, я только публикую этот материал, потому что он может быть полезен кому-то еще. Этот вопрос также был очень полезен для меня.

Ответы [ 3 ]

1 голос
/ 07 марта 2009

Поскольку библиотека lib - это просто контейнер, если вы связываете один и тот же файл .obj в обоих случаях, то, как сказал Брайан, они не должны (не могут?) Иметь значение.

Следует обратить внимание на то, что если вы изменили определение MyBase, вам, очевидно, потребуется перекомпилировать и библиотеку, и код, использующий ее. Например, если вы добавили новый виртуальный метод в MyBase перед методом value, тогда это испортит библиотеку, поскольку смещение значения v-таблицы будет другим.

1 голос
/ 07 марта 2009

Эта проблема возникает, когда библиотека и исполняемый файл были скомпилированы с различными определениями MyDerived класса (т.е. разными версиями файла .h / .hh / .hpp который объявляет MyDerived. Полностью очищает и перестраивает ваши проекты. За исключением этого, различные опции компилятора могут быть ответственными, хотя это несколько маловероятно.

Если проблема не устраняется после восстановления всего с нуля, то прибейте его путем создания пустого объекта MyDerived внутри getFloat в библиотеке. Используйте отладчик для сравнения vtable пустышки MyDerived (созданной в библиотеке) и vtable ссылки на объект MyDerived, переданной в качестве параметра (созданной в исполняемом файле). Что-то должно сразу появиться .

0 голосов
/ 07 марта 2009

Там не должно быть никакой разницы. Просто убедитесь, что файлы .h, которые вы включаете, точно соответствуют .lib, на который вы ссылаетесь. Я подозреваю, что вы можете ссылаться на старый файл .lib.

Если вы используете Visual Studio, вместо того, чтобы явно указывать файл .lib, просто щелкните правой кнопкой мыши по проекту и установите зависимости для проекта .lib. Таким образом, вы будете уверены, что он использует правильный файл .lib.

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