5

I am having small problem in making a global variable works. I am using Visual Studio 2008 and standard C++.

I have two projects, one is a static library and second one is a test program which uses this library. I have a global variable in global.h like

#ifndef GLOBAL_H
#define GLOBAL_H

#include <string>

extern std::string globalWord;

#endif // GLOBAL_H!

I have a global.cpp where I am initializing this variable. This variable is used inside my library project. I am setting a value to this variable from the test project, but that value is not getting reflected in the library project.

I have debugged and it shows the new value in test project, but when the control reaches the library project, this variable value shows empty. So is this global variable's scope only limited to the project where it belongs to?

Or is there a better way to do this? I don't want to modify my function or constructor parameters in my library to pass this value.

Any help would be great.

Edit:

Here is how this variable is declared in global.cpp

#include <string>
#include "../global.h"

std::string globalWord = "";

This is how I used it in my library

#include "../global.h"
string text = globalWord;

Thanks

Navaneeth K N
  • 15,295
  • 38
  • 126
  • 184
  • Show all the code. This should work as you've described it so something else must be wrong. – paxdiablo Feb 13 '09 at 02:05
  • That library you mention, Is it a separate DLL? is it a statically linked DLL? or are you loading it with `LoadLibrary()`? delayed load maybe? – shoosh Feb 13 '09 at 02:06
  • It is a static library. I have set in Project Dependencies of the test project. – Navaneeth K N Feb 13 '09 at 02:10
  • I'm with Pax -- now that you've shown the code, I believe this should just work. Could it be some unrelated problem, e.g. you're linking with an older version of the library? (E.g. you forgot to rebuild the Release version of the library.) Also are the two modules built with *identical* settings? – j_random_hacker Feb 13 '09 at 02:17
  • Wait a minute -- is "string text" in your library also a global variable? If so then you are hitting the "Static Initialisation Order Fiasco", a known issue with C++. See Matt's answer for a solution. – j_random_hacker Feb 13 '09 at 02:30
  • No. text is a local variable. – Navaneeth K N Feb 13 '09 at 02:32
  • @Appu: OK. Is this local variable in a constructor used to initialise a global variable, or in a function called by such a constructor? That is, has main() started to run by the time "string text = globalWord;" gets called? – j_random_hacker Feb 13 '09 at 02:38
  • In my test project, I am setting this global variable to some value, say "Foo". I need to get this value in the library. Yes, main started to run. I use UnitTest++ in the test project and this is an attempt to test a method without modifying it's parameters. Thanks for the help. – Navaneeth K N Feb 13 '09 at 02:44
  • @Appu - what exactly do you mean by "when the control reaches the library project"? Could you tell us exactly what you expect to be in the globalWord and test variables, and what you see in them in the debugger? – Michael Burr Feb 13 '09 at 03:31
  • I see a nothing in debugger. There is no value assigned. From my test project, I assign, globalWord = "Foo". Next line I can see globalWord has "Foo" in the debugger. But when the control reaches the code in library, debugger shows this value as empty. Thanks – Navaneeth K N Feb 13 '09 at 03:34
  • I've seen a similar problem a lib which creates a global var, and this lib is linked in two projects, in my case a dll, and an exe, each project has its own copy of the global var. – Ismael Feb 13 '09 at 14:39
  • Modifying it from the .exe didn't reflect in dll. My solution was to move the global away from the lib to the dll and export it. – Ismael Feb 13 '09 at 14:42
  • But I don't know if this is your case. In order to debug it you have to take a look at the address of each global. – Ismael Feb 13 '09 at 14:46
  • Another approach is to create a class which only contain a string, but you can add a constructor and put a breakpoint there, so you know when it is created. – Ismael Feb 13 '09 at 14:46

4 Answers4

9

Don't use global variables. Just don't. Much better, if you HAVE to have globally accessible data, is to use a global function which will return globalWord, like this:

std::string globalWord()
{
    static std::string word("Hi Mom");
    return word;
}

This saves you from initialization order issues (read Effective C++ item #4).

Matt
  • 10,434
  • 1
  • 36
  • 45
  • Thanks. So the string word will have a lifetime till the end of program? I need to set the value too. So can I have a SetGlobalWord method? If yes, where do I set the value, I mean to which variable? – Navaneeth K N Feb 13 '09 at 02:22
  • Matt, how do you change this variable to "Bye Dad", for example? – paxdiablo Feb 13 '09 at 02:24
  • 1
    @Matt: +1 as soon as you change the return value to a reference. Appu specifically needs to be able to change the value. – j_random_hacker Feb 13 '09 at 02:32
  • Also note that currently, on most C++ compilers other than g++, if you need to access globalWord() from multiple threads, you need to guard the definition of word with whatever mutex primitives your platform supplies. – j_random_hacker Feb 13 '09 at 02:34
  • @j_random_hacker, Since when does G++ do that automatically? The threading issue persists even with global variables, too. (After all, function statics are just scoped globals.) – strager Feb 13 '09 at 02:54
  • @ strager: J_random_hacker was referring to the problem of initialization. A static function variable is initialized on first use (unlike a global) and thus potentially problems in a threaded environment. G++ explicitly adds code to guarantee that the variable is only initialized once. – Martin York Feb 13 '09 at 05:21
  • Cont: Note. other multi-threaded access/synchronization problems still exist and must be explicitly handeled by the developer (just like any other language). – Martin York Feb 13 '09 at 05:23
  • @Matt: Yes using this technique is a good idea but does not (in this case) solve the problem you elude too. Initialization order is only a problem if global variables refer to each other in their constructors. If the global are independent then their is no problem. – Martin York Feb 13 '09 at 05:25
  • cont: Though by using this method you avoid future upgrade problems when the variables could potentially start to refer to each other. But the fact that you have global variables or a need to get around them is a bigger code smell. – Martin York Feb 13 '09 at 05:26
  • How about defining a global object (which has the getter/setters) and contains all those variables? – wmac Mar 25 '13 at 08:35
6

With the "extern" keyword, you're telling the compiler that the actual variable exists somewhere else. You should also create a variable with the same name without the extern, in one and only one place. Ordinarily you'll get an error from the linker if you define two of them, but if one's in the library and one's not it might not figure it out.

Edit: make sure global.cpp is only in the library or test program, not both.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
3

The problem is likely to be one of initialization order. When the program is linked, there are 2 places where globalWord is used in initialization:

  1. in the initialization of text ("string text = globalWord;")
  2. the initialization of globalWord itself

Unfortunately, the C++ standard does not specify the order of initialization of globals that come from different modules. Something similar to Matt's answer of using a function or a simple class (a singleton, for example) to access the global value is the usual way of enforcing a particular initialization order.

The C++ FAQ talks about this a little - if you plan to modify globalWord in your program, the situation is made a little more complex than they discuss because they don't seem to address setting the value hidden behind the "construct on first use" function. Typically something like that would require something like a singleton class.

Community
  • 1
  • 1
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • How does this explain that the debugger shows different contents in different contexts? – Mark Ransom Feb 13 '09 at 02:56
  • Good idea, but Appu just responded to my comment saying that 'text' is a local variable initialised after main() has started, at which point all globals have been initialised (in some order). So AFAIK the static initialisation order fiasco cannot be the problem here. – j_random_hacker Feb 13 '09 at 03:03
  • @Mark- You are right - this answer might not explain th ebehavior he's describing (though the debugging description is not entirely clear to me). I was basing my answer on the code snippets - hopefully they were copied (via the clipboard) from the actual code. – Michael Burr Feb 13 '09 at 03:24
2

The kind of behavior you describe seems more like a problem when you have a DLL, but you are saying that your library is static, which looks weird.

Anyway, take care with global variables in multiple libraries, if you have a shared code library (DLL) you'll get a value for each part. Check out this question, can be useful.

Community
  • 1
  • 1
Edwin Jarvis
  • 5,980
  • 6
  • 36
  • 41