Отсутствуют невиртуальные преобразователи и порядок наследования

У нас есть большая база кода на C ++, и после небольшого рефакторинга (добавлен один класс и переписаны некоторые связанные методы) мы начали получать ошибки компоновщика в GCC 3 и 4. Ошибками компоновщика были, в частности, «отсутствующие ссылки на не виртуальные преобразователи» в небольшие примеры программ, которые делят классы на подклассы в нашем большом SDK.

Поиск в Интернете не дал особых подсказок, кроме некоторых старых ошибок GCC, которые, похоже, были решены.

Признаки проблемы кажутся такими:

  • Оптимизация GCC 3.4.6 и 4.3.3 с -O2
  • Множественное наследование, включая случайное виртуальное наследование.
  • Изменение порядка наследования, скажем, с
    class Foo: public A, public B {} на
    class Foo: public B, public A {}
    для классов, в которых отсутствуют преобразователи, «решает» проблему.

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

Очевидно, что изменение порядка наследования на самом деле не решает проблему. Что еще это может быть?


person Adrian    schedule 14.04.2011    source источник
comment
Используете ли вы тот же уровень оптимизации для компоновки с библиотекой, который вы использовали для компиляции своей библиотеки?   -  person Karl von Moor    schedule 14.04.2011
comment
Вы перекомпилировали всю программу, библиотеки, файлы ресурсов, pch после изменения ()?   -  person RedX    schedule 15.04.2011
comment
У нас есть проверочная сборка, которая собирает все свежее каждый раз, когда она проверяется в системе управления версиями, так что да.   -  person Adrian    schedule 15.04.2011
comment
Или, скорее, у нас есть фиксированные предварительно скомпилированные сторонние библиотеки, такие как Boost и т. Д., Но весь наш код каждый раз перестраивается.   -  person Adrian    schedule 15.04.2011
comment
Это сообщение может означать, что виртуальная функция объявлена, но не определена (или определение не связано). Хотя это могло быть что-то еще. Не могли бы вы дословно процитировать одно из сообщений об ошибке?   -  person n. 1.8e9-where's-my-share m.    schedule 20.12.2011
comment
-O2 - обычное место проблемы в некоторых случаях. Я также столкнулся с проблемой в компиляторе g ++ 4.4.x.   -  person siddhusingh    schedule 05.04.2012
comment
Следует иметь в виду, что, вообще говоря, нет гарантии, что вы можете связать код из разных компиляторов C ++ или даже разных версий одного и того же компилятора C ++. Они используют разные соглашения для реализации функций C ++.   -  person NovaDenizen    schedule 04.09.2012
comment
У меня были проблемы с некоторыми ранними версиями gcc и виртуальными функциями. Решением было изменить порядок появления виртуальных функций и сделать его одинаковым для всех классов. Вы можете проверить и увидеть, не является ли такая проблема причиной ваших проблем.   -  person ipapadop    schedule 02.10.2012
comment
Я бы попробовал восстановить Boost и другие сторонние (статические) библиотеки. Я думаю, что если вы динамически связываетесь, вы должны быть в относительной безопасности.   -  person Mark McKenna    schedule 10.10.2012
comment
В таком случае, если вам нужно остаться с -O2, я бы попытался использовать гораздо более новую версию gcc. Или попробуйте лязгать. Затем перекомпилируйте все, включая внешние библиотеки, если возможно.   -  person Johan Lundberg    schedule 14.10.2012
comment
Спасибо за все предложения! К сожалению, у меня больше нет доступа к базе кода, но я оставлю это здесь на случай, если в будущем это поможет кому-то другому.   -  person Adrian    schedule 16.10.2012
comment
@ipapadop, это было бы грубым нарушением определения C ++. Я ожидал увидеть нечто подобное в самых первых бета-версиях компилятора C ++.   -  person vonbrand    schedule 08.02.2013
comment
@vonbrand Я согласен и видел это только раз в жизни в некоторых gcc 3.x   -  person ipapadop    schedule 08.02.2013


Ответы (2)


Если изменение порядка объявления базовых классов устраняет проблему, это, вероятно, означает, что один из базовых классов неправильно определяет то, что он объявил.

Например, если у вас есть объявление с (не виртуальным) методом Func в классе A и то же самое в классе B, но вы никогда не определяли его для класса A, то при первом вызове метода в вашем дочернем элементе версия класса A вызывается, но во время ссылки ссылка не найдена. Если вы измените порядок наследования, вместо этого компилятор вызовет B :: Func, который определен, и затем компоновщик найдет его.

ИМХО, это в любом случае плохой дизайн, так как там поведение будет сложно предсказать и отладить.

person xryl669    schedule 29.10.2012

Это может быть проблема с алмазом

если да, проверьте это ветка

person DjSol    schedule 16.10.2012