Точка останова не достигнута в глобальном статическом инициализированном классе в статически связанной библиотеке - PullRequest
3 голосов
/ 29 декабря 2010

Я испытал странное поведение на части VS2010.

Я добавил этот простой код в два файла .cpp и поместил точку останова в указанную строку кода

namespace {
   class TestClass
   {
   public:
      TestClass()
      {
         printf("");     // ### BREAKPOINT_HERE
      }
   };
}
TestClass a;

Странно то, что как только программа скомпилирована и запущена, точка останова в одном из файлов корректна, а в другом автоматически отключается с предупреждением: «Точка останова в настоящее время не будет достигнута. Для этого документа не было загружено никаких символов. '

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

Может кто-нибудь сказать мне, в чем может быть проблема?

Cheers, Паксас

Ответы [ 6 ]

1 голос
/ 29 декабря 2010

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

Чтобы понять, почему это так, вспомните время до C ++. Цель библиотеки состояла в том, чтобы упаковать все функции, которые вам могут понадобиться , в один файл. Компоновщик будет проходить через каждый модуль в библиотеке, где модуль определяется путем компиляции одного исходного файла. Если программе требуется символ, определенный в модуле, этот модуль будет связан; в противном случае он будет пропущен, чтобы неиспользованные части библиотеки не раздували приложение.

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

1 голос
/ 29 декабря 2010

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

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

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

1 голос
/ 29 декабря 2010

Раньше я сталкивался с подобной проблемой, хотя тогда я определил код регистрации в отдельном проекте LIB. Оказывается, компоновщик оптимизировал мои объекты! Мое решение состояло в том, чтобы ссылаться на эти «объекты регистрации» в функции. Затем я вызвал функцию из моего приложения. Может быть, что-то подобное происходит здесь? Попробуйте отключить оптимизацию всей программы и посмотрите, что произойдет. Возможно, вам придется что-то сделать, чтобы оптимизатор не воспринимал эти объекты как мертвый код. (Мне бы хотелось, чтобы в Visual C ++ были атрибуты для пометки кода как не мертвого ...)

Обновление: Если не считать чистого способа пометить объекты как мертвые, мне пришлось прикоснуться к коду в обоих проектах. В проекте LIB я определил функции, а не глобальные объекты. В проекте приложения я определил функции, которые вызывали эти функции.

Что вы можете сделать, это:

// Registrations.cpp
#ifdef EXPORT_REGISTRATIONS
#define REGISTRATION_CODE(theClass) \
       void register_##theClass##_function() { \
           // Code for registering your class \
       }
#else
#define REGISTRATION_CODE(theClass) \
       // Declare a function prototype for the function in LIB \
       void register_##theClass##_function(); \
       struct theClass##importer { \
           theClass##importer() { \
               // Call into LIB \
               register_##theClass##_function(); \
           } \
       } g_##theClass##importerInstance; \
#endif

REGISTRATION_CODE(MyClass);
REGISTRATION_CODE(MyOtherClass);

Затем в проекте LIB убедитесь, что определено EXPORT_REGISTRATIONS. Это сгенерирует функции, которые выполняют фактическую регистрацию, которую вы собираетесь делать. В проекте приложения убедитесь, что EXPORT_REGISTRATIONS не определено . #include "<path to lib project>\Registrations.cpp" в проекте приложения. Это сгенерирует глобальные объекты (например, ваши оригинальные), которые вызывают функции, определенные в проекте LIB.

Так я решил свою проблему. Ваш пробег может варьироваться. :)

0 голосов
/ 29 декабря 2010

Я нашел некоторые новые факты, которые могут пролить свет на ситуацию, и отредактировал главное сообщение.

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

Все решение компилируется в режиме отладки с отключенной оптимизацией.Проект, в котором находятся файлы, скомпилирован как статическая библиотека.

0 голосов
/ 29 декабря 2010

Пожалуйста, отбросьте все, что вы делаете, и прочитайте это сейчас .(Также прочитайте следующий раздел, 10.15.)

Во-вторых, если случайно вы не попали в эту конкретную проблему, не могли бы вы показать определение для getClassesRegistry?А вы установили там точку останова или использовали какую-то другую диагностику, чтобы убедиться, что этот метод действительно не вызывается?

0 голосов
/ 29 декабря 2010

использовал тот факт, что статические объекты инициализируются перед вызовом main (), чтобы заполнить его

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

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