开发者

Breakpoint not hit in a global static initialized class in a statically linked lib

I've experienced a weird behavior on VS2010 part.

I've added this simple code to two .cpp files, and placed a breakpoint on the specified line of code

namespace {
   class TestClass
   {
   public:
      TestClass()
      {
        开发者_运维问答 printf("");     // ### BREAKPOINT_HERE
      }
   };
}
TestClass a;

The weird thing is that once the program is compiled and run, breakpoint in one of the files is correct, and in the other one gets automatically disabled with a warning: 'The breakpoint will not currently be hit. No symbols have been loaded for this document.'

Both .cpp files were created in the same fashion and have the very same properites. The project they're in has a significant amount of files, but the file I've problem with wasn't added most recently - there are newer files that don't exhibit the problem.

Can anyone tell me what can be the problem?

Cheers, Paksas


I think the problem is not with the compiler, but with the linker. If it doesn't see any explicit accesses to a symbol in a module in a library, it will not link the module. Thus any static objects in that module will never exist.

To realize why this is so, think back to a time before C++. The purpose of a library was to package up every function you might need into a single file. The linker would go through each module in the library, where a module is defined by compiling a single source file. If the program required a symbol defined in the module, that module would get linked; if not, it would be skipped so that unused parts of the library didn't bloat the application.

This process is recursive, so if module A requires something from module B, module B will be linked even if the program didn't require it directly. This is the key to working around the problem - make sure the main module of your library accesses at least one object or function from every module that contains your static initializers.


You have defined the a object in two different files. You have violated the one-definition rule, and the compiler is free to do whatever it likes in that situation.

Give one of your variables a different name, and you should be able to observe both of them being initialized.

(The multiple definitions of TestClass are fine for two reasons. One is that they're in separate namespaces, and the other is that even if they weren't in separate namespaces, their definitions would be identical, and the one-definition rule makes an exception for that.)


I have run into a similar problem before, although then I had defined the registering code in a separate LIB project. It turns out that the linker optimized away my objects! My solution was to reference these "registration objects" in a function. I then called the function from my application. Maybe something like that is happening here? Try turning off whole program optimization and see what happens. You might have to do something to keep the optimizer from treating this objects as dead code. (I wish Visual C++ had attributes for marking code as non-dead...)

Update: Short of finding a clean way of marking objects as non dead, I had to touch the code in both projects. In the LIB project, I defined functions rather than global objects. In the app project, I defined functions that called these functions.

What you can do is this:

// 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);

Then in the LIB project, make sure EXPORT_REGISTRATIONS is defined. This will generate the functions that perform the actual registration that you intend to do. In the app project, make sure EXPORT_REGISTRATIONS isn't defined. #include "<path to lib project>\Registrations.cpp" in the app project. This will generate global objects (like your original ones) that call into the functions defined in the LIB project.

This is how I solved my problem. Your mileage may vary. :)


took advantage of the fact that static objects get initialized before main() is called to populate it

I think you are missing the fact that compiler is allowed to defer dynamic initialization of non-local variables with static storage duration until their first use. If your code never uses those registration classes, compiler will not create code to perform dynamic initialization at all.


Please, drop everything else you're doing and read this now. (Also read the following section, 10.15.)

Second, if by chance you're not falling into that particular problem, could you please show the definition for getClassesRegistry? And have you set a breakpoint there, or used some other diagnostic to verify that that method really isn't being called?


I've found some new facts that can shed the light on the situation and edited the main message.

Try turning off whole program optimization and see what happens. You might have to do something to keep the optimizer from treating this objects as dead code.

Whole solution is compiled in debug mode with all optimizations turned off. The project the files are in is compiled as a static library.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜