1

I broke my Visual Studio project (2015, C++) into three pieces:

  • The main application in a static library
  • The executable which just has a main function
  • Unit tests which use the static .lib file so that they can import the required classes and do the unit tests on them.

Before I split it into a lib/exe/tests, the main application was just a standalone executable, and it worked perfectly fine.

Now I can't run the executable with only the main function, nor the unit tests as a certain pointer is always null. The only main difference is that I'm using a raw pointer in this example, but I was using a unique_ptr in my code (currently however I switched to the raw pointer just to make sure this following example is as accurate as possible and it didn't magically compile/run properly with the raw pointer).

The code looks very similar to the following (the extra code has been removed):

// console.hpp
extern Console *console;

The implementation cpp file (only of what is needed):

// console.cpp
Console *console = new Console();

Now in some unrelated function, this code fails due to the console pointer being a nullptr:

// some_other_file.cpp
#include "console.hpp"

    // Inside some function...
    console->doSomething();  // console is NULL

Again, the code I have worked perfectly fine when it was in one project. Regardless, it all compiles fine with no linking errors even though it has been broken into 3 pieces, but now that pointer is always null.

As a last interesting note, the non-pointer variables that are global and extern do work. Is this something limited to pointers/unique_ptrs?

Is this something fixable by a singleton pattern?

7
  • That's the same setup I use. I'm not sure how to reproduce. Did you say console is a global variable initialized before main? Have you tried a breakpoint? Perhaps an initialize function would fix this. Commented Aug 17, 2016 at 16:35
  • Have you added the library in your project settings, or are you just including the header file? Second thought, you'd get a linkage error for console if you haven't linked that library, so it has to be something else... Commented Aug 17, 2016 at 16:41
  • That would give link errors, not a runtime issue. Commented Aug 17, 2016 at 16:43
  • @Water Console *console = new Console(); -- Are you sure this is the exact code you have? That console is not the same as your extern variable which happens to have the same name. Commented Aug 17, 2016 at 16:53
  • 1
    @PaulMcKenzie I copy pasted it. However I think you're onto something, it appears other code is getting called before the main function that don't let the global variable get initialized. Is there a way to ensure that the variable is set before being used? I don't know if that will require changing the code to use a singleton pattern, or if there is a way to make sure the console is run before everything else (of which I don't know how to do currently). Commented Aug 17, 2016 at 16:55

1 Answer 1

1

The clue is in this comment: "it appears other code is getting called before the main function that don't let the global variable get initialized."

The code referencing console is probably running as part of the initialization of another global and, in this case, is happening before the initialization of console. You have to be very careful to be sure that you're not depending on the order of the global initializers. You were probably getting lucky before you split the program, and now your luck has run out.

The easiest way to fix it is to use a singleton pattern. Instead of having other parts of the program directly reference the pointer, you have them call a function that returns the pointer, and that function will initialize it the first time. This ensures that it's initialized before it's used.

Here's a common pattern for it:

Console *GetConsole() {
    static Console *console = new Console();
    return console;
}

Now console is no longer a global variable. Everything that wants to access the console calls GetConsole instead.

The function-local static variable will be initialized the first time the function is called, and after that it just returns the value. If you have multiple threads and an older compiler, you have to do more work to protect against a possible race condition. Modern compilers should do the initialization in a thread-safe way.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.