20

Well, I'm learning C++ and never really learned how to do stuff that is not OO. I'm trying to get a bit more experience coding in C style.

GobalInformation.h

#pragma once

#ifndef GLOBALINFORMATION_H
#define GLOBALINFORMATION_H

#include "MapInformation.h"

namespace gi {
    MapInformation mapInf;
};

#endif

I would like to be able to access gi::mapInf from every header and cpp in my project. Right now I'm including globalinformation.h in every header, so I'm getting linker errors with multiple definitions.

How can I work around the problem?

9
  • 3
    You may think now that you want this global variable, but I assure you will regret it. Commented Nov 29, 2011 at 20:12
  • 1
    @BjörnPollex elaborate please
    – xcrypt
    Commented Nov 29, 2011 at 20:14
  • OT: Why do you use #pragma once and header guards (BTW, without unique identifiers => dangerous)?
    – Andre
    Commented Nov 29, 2011 at 20:28
  • @Andre Hmm, I read it at wikipedia once it might be good to do it : en.wikipedia.org/wiki/Pragma_once
    – xcrypt
    Commented Nov 29, 2011 at 20:32
  • 1
    @xcrypt: When using header guards you should append a unique part to avoid name clashes. You could add a GUID like so: #ifndef GLOBALINFORMATION_H_8FF7B23E1B4D11E18852C5D64824019B, #define GLOBALINFORMATION_H_8FF7B23E1B4D11E18852C5D64824019B. If you don't need portability I would recommend to only use #pragma once if your compiler supports it.
    – Andre
    Commented Nov 30, 2011 at 12:22

5 Answers 5

36

In header file only do

namespace gi {
    extern MapInformation mapInf;
};

In CPP file provide the actual definition.

namespace gi {
    MapInformation mapInf;
};

It will work as you intend.

If you are using the MapInformation across dynamic link library boundaries you might have to link against the library that includes the definition cpp file. Also on Window you might have to use dllimport/dllexport

4
  • 1
    Note that the definition must be in exactly one translation-unit. Commented Nov 29, 2011 at 20:10
  • in globalinformation.cpp I should do "MapInformation mapInf;"?
    – xcrypt
    Commented Nov 29, 2011 at 20:12
  • 1
    @xcrypt .. I have updated my answer to reflect what to do in CPP file Commented Nov 29, 2011 at 20:13
  • what does that mean: "f you are using the MapInformation across dynamic link library boundaries you might have to link against the library that includes the definition cpp file." can you explain more?
    – Fractale
    Commented Jun 14, 2017 at 0:31
17

Be aware that having globals in multiple compilation units can easily lead to order-of-initialization problems. You may wish to consider replacing each global with a function that returns a reference. In your case, put this in one cpp file and declare it in the header:

namespace gi {
    MapInformation& getMapInf()
    {
        static MapInformation result;
        return result;
    }
}
6
  • 1
    Could you perhaps explain what is the cause of this order-of-intialization problem in your answer?
    – xcrypt
    Commented Nov 29, 2011 at 20:26
  • 4
    @xcrypt: The order in which global objects are initialized is unspecified (across TUs), so if you have one global object that requires another one, you can't be certain that they'll be initialized in the correct order. Having a local static object (which is essentially also global, just with restricted visibility) avoids this because you are guaranteed that the object will have been constructed by the time getMapInf() returns.
    – Kerrek SB
    Commented Nov 29, 2011 at 20:59
  • I suppose this function should be inlined or declared extern? Well, I had to, anyway
    – xcrypt
    Commented Nov 29, 2011 at 21:46
  • Good suggestion, but I have another question: How can I set the "global" variable in your case? How can I write a set-Method?
    – xMutzelx
    Commented Dec 11, 2017 at 8:56
  • @xMutzelx, You can set or get the value of the global by using the reference returned by getMapInf(). E.g. gi::MapInformation otherMapInf(); getMapInf() = otherMapInf(); Commented Feb 15, 2019 at 17:02
3

Global variables are C, but namespaces are C++. There is a good discussion on using global variables and how they can be replaced by Singleton pattern: Globals and Singletons

And here is a simple sample: CPP/Classes/Singleton

2

Perhaps a better solution is to create a global object that contains all your global data. Then pass a smart pointer to the classes that actually need to access this shared global data. Example:

class GlobalData
{
public:
    int ticks_;
};   


//Other file
class ThatNeedsGlobalData
{
public:
ThatNeedsGlobalData(std::shared_ptr<GlobalData> globalData);
};

This will save you some trouble.

Good luck!

2
  • That would also be a possible solution, so I will vote up. But one of the reason I want it as global is to prevent each class from having a reference to the information (saving memory). It might not matter much in the end, but hey, I think it's cool :p
    – xcrypt
    Commented Nov 29, 2011 at 20:29
  • So you want to save the size of a pointer/smart pointer in each class that needs access to the global data? Ok. Just try it and see if you think it is worth it. You can always try other solutions later.
    – mantler
    Commented Nov 29, 2011 at 20:35
1

Here are a few things that you need to take care of while trying to use global variables the way you have used.

  1. Ensure that all the header files that the header files that GobalInformation.h includes are also enclosed insides #ifndefs. (I could not see mapinformation.h so I assume you have done it)

  2. Just like CPP, C compiler also does not ensure order of the initialization of variables in different translation units(different C/CPP files). Hence declare the header file as

    //GlobalInformation.h
    
    namespace gi {
        extern MapInformation mapInf;
    };
    
  3. In a function that you know would be called first initialize the variable. This way lazy-initialization can also be acheived in C.

1
  • I'm not sure what you mean with [2], please elaborate? Seems important
    – xcrypt
    Commented Nov 29, 2011 at 20:57

Not the answer you're looking for? Browse other questions tagged or ask your own question.