Globals

A

Andrea Crotti

I have the following situation:

I need to get some global variables from the outside (configuration
file) and keep them somewhere globally accessible. (For reading the
files I might use boost::program_options.)

So I did something like:

--8<---------------cut here---------------start------------->8---
#ifndef GLOBALS_H
#define GLOBALS_H
#include <iostream>
#include "Environment.h"

namespace GLOBALS
{
static int num_landmarks;
static int trace_length;
static int history_size;
static int distribution_size;
static Environment *environment;
// see why this error
static ostream *out;
}
#endif /* GLOBALS_H */
--8<---------------cut here---------------end--------------->8---

But actually it doesn't work, since if I do in one class

GLOBALS::history_size = 10;

in another class that value is still 0.

So I guess it doesn't work.
I also want to do something less stupid than a global state, but as long
as I don't understand very well the problem and how is best to construct
objects it would be the easiest way.

But what's wrong with this approach?
 
S

Saeed Amrollahi

I have the following situation:

I need to get some global variables from the outside (configuration
file) and keep them somewhere globally accessible.  (For reading the
files I might use boost::program_options.)

So I did something like:

--8<---------------cut here---------------start------------->8---
#ifndef GLOBALS_H
#define GLOBALS_H
#include <iostream>
#include "Environment.h"

namespace GLOBALS
{
    static int num_landmarks;
    static int trace_length;
    static int history_size;
    static int distribution_size;
    static Environment *environment;
    // see why this error
    static ostream *out;}

#endif /* GLOBALS_H */
--8<---------------cut here---------------end--------------->8---

But actually it doesn't work, since if I do in one class

GLOBALS::history_size = 10;

in another class that value is still 0.

So I guess it doesn't work.
I also want to do something less stupid than a global state, but as long
as I don't understand very well the problem and how is best to construct
objects it would be the easiest way.

But what's wrong with this approach?

Hi

No. It isn't true. The non-local objects (that is, global,
namespace, and class static variables) is initialized
(constructed) before main() is invoked, and you can access
them globally. So they are visible to all program entities.
consider:

namespace Global {
static int hist_size = 10;
}

struct C {
int i_;
C(int i = Global::hist_size) { i_ = i; }
static int GetHistSize() { return Global::hist_size; }
static void SetHistSize(int i) { Global::hist_size = i; }
};

#include <iostream>

int main()
{
using namespace std;
int i = Global::hist_size; // i = 10;
C c; // c.i_ = 10
Global::hist_size++;
C c2; // c2.i_ = 11
C::SetHistSize(C::GetHistSize() + 89); // hist_size = 100
}

The Global namespace and class C may be in other files.

Regards,
-- Saeed Amrollahi
 
A

Andrea Crotti

Saeed Amrollahi said:
Hi

No. It isn't true. The non-local objects (that is, global,
namespace, and class static variables) is initialized
(constructed) before main() is invoked, and you can access
them globally. So they are visible to all program entities.
consider:

namespace Global {
static int hist_size = 10;
}

struct C {
int i_;
C(int i = Global::hist_size) { i_ = i; }
static int GetHistSize() { return Global::hist_size; }
static void SetHistSize(int i) { Global::hist_size = i; }
};

#include <iostream>

int main()
{
using namespace std;
int i = Global::hist_size; // i = 10;
C c; // c.i_ = 10
Global::hist_size++;
C c2; // c2.i_ = 11
C::SetHistSize(C::GetHistSize() + 89); // hist_size = 100
}

The Global namespace and class C may be in other files.

Regards,
-- Saeed Amrollahi


Well this
--8<---------------cut here---------------start------------->8---
#include <iostream>

using namespace std;

namespace Global {
static int x;
}

int main() {
Global::x = 10;
cout << Global::x;
return 0;
}
--8<---------------cut here---------------end--------------->8---

also works for me, but if they're in different files it doesn't.
Maybe the order of inclusion of the headers can make any difference?
 
S

Saeed Amrollahi

Well this
--8<---------------cut here---------------start------------->8---
#include <iostream>

using namespace std;

namespace Global {
    static int x;

}

int main() {
    Global::x = 10;
    cout << Global::x;
    return 0;}

--8<---------------cut here---------------end--------------->8---

also works for me, but if they're in different files it doesn't.
Maybe the order of inclusion of the headers can make any difference?

Actually, I declare the Global namespace in global.h and class C in
c.h.
You know, C++ guarantees, x is initialized (to 0) before the the main
is invoked.
Also, C++ guarantees in a translation unit, the non-local objects are
constructed
and initialized in the order of declaration, but the order of
construction of
non-local objects in two or more translation units is implementation-
dependent.
But, I guess your question is:
// global.h
namespace Global {
static int x; // initialized to 0
}

// 1.cpp
#include "global.h"
void f()
{
++Global::x; // x = 1;
}

// 2.cpp
#include "global.h"
void g()
{
--Global::x; // x = -1
}

It's a guarantee x is initialized to 0, at first place.
It is completely to you, call first f() or g().
You can check its current value. It's tedious, but manageable.
Another thing, about order of inclusion. It's obvious, just
one copy of global.h is included in your program and you have to
use include guard. After inclusion, x is initialized to 0 ...
In advance, I'm sorry, if I didn't get your purpose yet.

Hope that helps
-- Saeed Amrollahi
 
A

Andrea Crotti

Saeed Amrollahi said:
Actually, I declare the Global namespace in global.h and class C in
c.h.
You know, C++ guarantees, x is initialized (to 0) before the the main
is invoked.
Also, C++ guarantees in a translation unit, the non-local objects are
constructed
and initialized in the order of declaration, but the order of
construction of
non-local objects in two or more translation units is implementation-
dependent.
But, I guess your question is:
// global.h
namespace Global {
static int x; // initialized to 0
}

// 1.cpp
#include "global.h"
void f()
{
++Global::x; // x = 1;
}

// 2.cpp
#include "global.h"
void g()
{
--Global::x; // x = -1
}

It's a guarantee x is initialized to 0, at first place.
It is completely to you, call first f() or g().
You can check its current value. It's tedious, but manageable.
Another thing, about order of inclusion. It's obvious, just
one copy of global.h is included in your program and you have to
use include guard. After inclusion, x is initialized to 0 ...
In advance, I'm sorry, if I didn't get your purpose yet.

Hope that helps
-- Saeed Amrollahi

Yes thanks that's very clear..
The only thing is that doing more or less the same you're doing here I
dont't get the value I set.
But maybe now I understood why.

If I have

--8<---------------cut here---------------start------------->8---
#include "Globals.h"
namespace Global {
static int x; // initialized to 0
}
--8<---------------cut here---------------end--------------->8---

and I want to use x as in a constructor initialization list

X::X () : x(Global::x)
{
cout << Global::x;
}

and I do

int main() {
Global::x = 10;
X var;
}

I don't get the value I want but I still have 0.
Does it make sense? And how to avoid it?
 
N

Niklas Holsti

Andrea said:
I have the following situation:

I need to get some global variables from the outside (configuration
file) and keep them somewhere globally accessible. (For reading the
files I might use boost::program_options.)

So I did something like:

--8<---------------cut here---------------start------------->8---
#ifndef GLOBALS_H
#define GLOBALS_H
#include <iostream>
#include "Environment.h"

namespace GLOBALS
{
static int num_landmarks;
static int trace_length;
static int history_size;
static int distribution_size;
static Environment *environment;
// see why this error
static ostream *out;
}
#endif /* GLOBALS_H */
--8<---------------cut here---------------end--------------->8---

But actually it doesn't work, since if I do in one class

GLOBALS::history_size = 10;

in another class that value is still 0.

So I guess it doesn't work.
I also want to do something less stupid than a global state, but as long
as I don't understand very well the problem and how is best to construct
objects it would be the easiest way.

But what's wrong with this approach?

It seems to me, from my limited understanding of C++, that your
globals.h is defining *file-scope* variables with "internal linkage",
because of the "static" keywords in each definition.

If so, when you include globals.h in different compilations, *different*
variables called num_landmarks etc. are created for each compilation. If
the two classes you mention are compiled from different *.cpp files,
each of which includes globals.h, the assignment to history_size in one
class assigns to one of these file-scope variables, and the other class
uses and sees another of these file-scope variables.

To access the same global variable from different compilations, that
variable should have "external linkage".

Change "static" to "extern" in globals.h, or just remove it.

See
http://smart2help.com/e-books/ticpp-2nd-ed-vol-one/Chapter10.html#Index1744
for more explanation.
 
A

Andrea Crotti

It seems to me, from my limited understanding of C++, that your
globals.h is defining *file-scope* variables with "internal linkage",
because of the "static" keywords in each definition.

If so, when you include globals.h in different compilations,
*different* variables called num_landmarks etc. are created for each
compilation. If the two classes you mention are compiled from
different *.cpp files, each of which includes globals.h, the
assignment to history_size in one class assigns to one of these
file-scope variables, and the other class uses and sees another of
these file-scope variables.

To access the same global variable from different compilations, that
variable should have "external linkage".

Change "static" to "extern" in globals.h, or just remove it.

See
http://smart2help.com/e-books/ticpp-2nd-ed-vol-one/Chapter10.html#Index1744
for more explanation.

Ah yes that would explain the behaviour, but actually removing the
static doesn't work, since then it's declared multiple times...

What if instead I declare everything in the .cpp file and then I compile
it together?
Is that only one instance then?
 
S

Saeed Amrollahi

Yes thanks that's very clear..
The only thing is that doing more or less the same you're doing here I
dont't get the value I set.
But maybe now I understood why.

If I have

--8<---------------cut here---------------start------------->8---
#include "Globals.h"
namespace Global {
    static int x;  // initialized to 0}

--8<---------------cut here---------------end--------------->8---

and I want to use x as in a constructor initialization list

X::X () : x(Global::x)
{
        cout << Global::x;

}

and I do

int main() {
    Global::x = 10;
    X var;

}

I don't get the value I want but I still have 0.
Does it make sense? And how to avoid it?

I ran the your sample (global.h, x.h and main.cpp) on
Visual Studio 2008 and GCC 4.5.0. The output is 10.
Also, I switched the order of header file inclusion, and it is OK.
I don't understand! the object var is created using the very last
instruction
Global::x = 10;
and the data member X::x initialized to 10.
BTW, you can't count on implementation-dependent behavior.
To make sure, put all non-local objects construction/initialization
into one .cpp file. In that way, there is a guarantee all objects are
initialized
in the order of declaration.

Regards,
-- Saeed Amrollahi
 
A

Andrea Crotti

Saeed Amrollahi said:
I ran the your sample (global.h, x.h and main.cpp) on
Visual Studio 2008 and GCC 4.5.0. The output is 10.
Also, I switched the order of header file inclusion, and it is OK.
I don't understand! the object var is created using the very last
instruction
Global::x = 10;
and the data member X::x initialized to 10.
BTW, you can't count on implementation-dependent behavior.
To make sure, put all non-local objects construction/initialization
into one .cpp file. In that way, there is a guarantee all objects are
initialized
in the order of declaration.

Regards,
-- Saeed Amrollahi

I tried again with a very simple example
--8<---------------cut here---------------start------------->8---
#include <iostream>

using namespace std;

namespace Global {
static int x;
}

class Cls {
public:
int x;
Cls () : x(Global::x) {}
};

int main() {
Global::x = 10;
cout << Global::x;

Cls c;
cout << c.x;
return 0;
}
--8<---------------cut here---------------end--------------->8---

and it actually works as expected.
Then I try to put everything in the cpp instead to see what happens..
 
A

Andrea Crotti

This problem is really annoying, so here it is

testTrace.cpp:
--8<---------------cut here---------------start------------->8---
// -*- compile-command: "g++ testTrace.cpp Trace.cpp"-*-
#include <iostream>
#include "Globals.h"
#include "Trace.h"

using namespace std;

int main()
{
GLOBALS::trace_length = 10;
cout << GLOBALS::trace_length << endl;
Trace t;

return 0;
}
--8<---------------cut here---------------end--------------->8---


Trace.h
--8<---------------cut here---------------start------------->8---
#ifndef TRACE_H
#define TRACE_H

#include <map>
#include <vector>
#include "RingBuffer.h"
#include "PadNodeID.h"
#include "Globals.h"

class Trace
{
private:
RingBuffer<PadNodeID> empty;
std::map<PadNodeID, PadNodeID> trace;

public:
Trace();
};

#endif /* TRACE_H */
--8<---------------cut here---------------end--------------->8---

Trace.cpp
--8<---------------cut here---------------start------------->8---
#include <iostream>
#include "Globals.h"
#include "Trace.h"
#include "PadNodeID.h"

Trace::Trace () : empty(GLOBALS::trace_length)
{
std::cout << GLOBALS::trace_length;
}
--8<---------------cut here---------------end--------------->8---


Globals.h
--8<---------------cut here---------------start------------->8---
#ifndef GLOBALS_H
#define GLOBALS_H

#include <iostream>
#include "Environment.h"
#include "Globals.h"

namespace GLOBALS
{
static int num_landmarks;
static int trace_length;
static int history_size;
static int distribution_size;
static Environment *environment;
// see why this error
static ostream *out;
}

#endif /* GLOBALS_H */
--8<---------------cut here---------------end--------------->8---

The guards are there, so it should be actually included only once, BUT
the second time I print the variable in the constructor is ALWAYS 0!!

Anything else or a completely different approach I could follow?

And the second problem is that I can't declare the map like that,
because the RingBuffer constructor is

RingBuffer(size_t max_size) : max_size(max_size) {};

The only way I see now is to add a default null constructor and set the
value later, but I don't really like it that much...

I solved that for other types using the initialization in the
Constructor but I don't understand how to do it here...
 
A

Alf P. Steinbach /Usenet

* Andrea Crotti, on 01.11.2010 17:30:
This problem is really annoying, so here it is

testTrace.cpp:
--8<---------------cut here---------------start------------->8---
// -*- compile-command: "g++ testTrace.cpp Trace.cpp"-*-
#include<iostream>
#include "Globals.h"
#include "Trace.h"

using namespace std;

int main()
{
GLOBALS::trace_length = 10;
cout<< GLOBALS::trace_length<< endl;
Trace t;

return 0;
}
--8<---------------cut here---------------end--------------->8---


Trace.h
--8<---------------cut here---------------start------------->8---
#ifndef TRACE_H
#define TRACE_H

#include<map>
#include<vector>
#include "RingBuffer.h"
#include "PadNodeID.h"
#include "Globals.h"

class Trace
{
private:
RingBuffer<PadNodeID> empty;
std::map<PadNodeID, PadNodeID> trace;

public:
Trace();
};

#endif /* TRACE_H */
--8<---------------cut here---------------end--------------->8---

Trace.cpp
--8<---------------cut here---------------start------------->8---
#include<iostream>
#include "Globals.h"
#include "Trace.h"
#include "PadNodeID.h"

Trace::Trace () : empty(GLOBALS::trace_length)
{
std::cout<< GLOBALS::trace_length;
}
--8<---------------cut here---------------end--------------->8---


Globals.h
--8<---------------cut here---------------start------------->8---
#ifndef GLOBALS_H
#define GLOBALS_H

#include<iostream>
#include "Environment.h"
#include "Globals.h"

namespace GLOBALS
{
static int num_landmarks;
static int trace_length;
static int history_size;
static int distribution_size;
static Environment *environment;
// see why this error
static ostream *out;
}

#endif /* GLOBALS_H */
--8<---------------cut here---------------end--------------->8---

The guards are there, so it should be actually included only once, BUT
the second time I print the variable in the constructor is ALWAYS 0!!

Anything else or a completely different approach I could follow?

It seems to me your question has already been answered up-thread.

By declaring the variables as 'static' you make them local to the compilation unit.

Each compilation unit where you include the [Globals.h] header gets its own set
of variables.


Cheers & hth.,

- Alf
 
A

Andrea Crotti

Alf P. Steinbach /Usenet said:
It seems to me your question has already been answered up-thread.

By declaring the variables as 'static' you make them local to the compilation unit.

Each compilation unit where you include the [Globals.h] header gets
its own set of variables.


Cheers & hth.,

- Alf

Ah true you're right, but if I don't declare them static I get
--8<---------------cut here---------------start------------->8---
/tmp/cc08z3Tl.o:(.bss+0x4): multiple definition of `GLOBALS::trace_length'
/tmp/ccvjZwsi.o:(.bss+0x4): first defined here
--8<---------------cut here---------------end--------------->8---

for all of them...
 
A

Andrea Crotti

Leigh Johnston said:
You need to declare them "extern" in the header file; did you ignore
my other reply stating this?

/Leigh

Ah sorry I've read and tried but I still got

namespace GLOBALS
{
extern int num_landmarks;
extern int trace_length;
extern int history_size;
extern int distribution_size;
extern Environment *environment;
//why this error
extern ostream *out;
}

--8<---------------cut here---------------start------------->8---
testTrace.cpp:(.text+0xe): undefined reference to `GLOBALS::trace_length'
testTrace.cpp:(.text+0x18): undefined reference to `GLOBALS::trace_length'
--8<---------------cut here---------------end--------------->8---

So I'm not sure I got it yet, I declare them in the .h file, and in
theory I have to declare as extern in the other files when I use them.

Declaring them extern in the header doesn't sound correct already..
 
J

Juha Nieminen

Andrea Crotti said:
namespace GLOBALS
{
static int num_landmarks;
static int trace_length;
static int history_size;
static int distribution_size;
static Environment *environment;
// see why this error
static ostream *out;
}

You are doing it wrong.

You declare (usually in a header file) a global variable with the
'extern' keyword, not the 'static' keyword, like this:

namespace GLOBALS
{
extern int num_landmarks;
}

Then you have to define that variable in a compilation unit, like this:

int GLOBALS::num_landmarks = 123;

Note that if what you want to declare is a compile-time constant, you
can do it directly in the declaration, without the need for a definition.
In this case you use 'const' instead of 'extern', like this:

namespace GLOBALS
{
const int compile_time_constant = 1234;
}
 
A

Andrea Crotti

Sherm Pendley said:
You need to declare them as "extern" in the header, then define them
(*without* static!) in a single .cpp file.

sherm--

Ok then it finally works :D

Probably I didn't want to try this method because repeating twice the
same thing doesn't look very right to me..

This almost copy & paste is really the only way to go here?
The other option is a singleton class right (which is not different from
global state so doesn't really help).

The other option would be to pass a "configuration" object to all the
various classes, but that's also terribly ugly and annoying...

Better would be to pass only the parameters needed to each class, but I
can still do it keeping the global namespace variables as a container...
 
P

Paul N

Ok then it finally works :D

Probably I didn't want to try this method because repeating twice the
same thing doesn't look very right to me..

I think some people get round the problem using #defines. For
instance, in globals.h you have stuff like:

#ifndef THIS_ONE
extern
#endif
int num_landmarks;

and then in all but one of your .cpp files you simply:

#include "globals.h"

but in one of them, you have

#define THIS_ONE
#include "globals.h"
#undef THIS_ONE

If you think this looks nicer, feel free to do it this way. But I'll
understand if you don't think it's an improvement.

Paul.
 
A

Andrea Crotti

Again on the "Globals" problem.
Since I also have an option parser, to avoid repetition and other
annonying things this approach

namespace GLOBALS
{
int num_landmarks;
int trace_length;
int history_size;
int distribution_size;
Environment *environment;
ostream *out;

is no longer good.
I need a class which stores a map where for example I keep a mapping
like

conf["num_landmarks"] = 3;
and so on.

So how do I make a class for only one object without using the annoying
singleton.
I actually don't care that it could be called more times (which won't).

Should I define the class (as extern??) in the header file and in the
..cpp allocate an object of it?
 
A

Andrea Crotti

Andrea Crotti said:
Again on the "Globals" problem.
Since I also have an option parser, to avoid repetition and other
annonying things this approach

namespace GLOBALS
{
int num_landmarks;
int trace_length;
int history_size;
int distribution_size;
Environment *environment;
ostream *out;

is no longer good.
I need a class which stores a map where for example I keep a mapping
like

conf["num_landmarks"] = 3;
and so on.

So how do I make a class for only one object without using the annoying
singleton.
I actually don't care that it could be called more times (which won't).

Should I define the class (as extern??) in the header file and in the
.cpp allocate an object of it?

Ok I thought something like
--8<---------------cut here---------------start------------->8---
class Globals
{
private:
std::map<string, string> config;

public:
Globals();
string operator[](string& idx) { return config[idx]; }
};

extern Globals CONFIG;
--8<---------------cut here---------------end--------------->8---

in the header would work, but the operator[] doesn't work as I thought.
How do I pass a reference to a string to it?
I would like to be able to do

CONFIG["variable"] = 10;

for example, but I guess that's not casted to string reference in C++...
 
V

Victor Bazarov

Andrea Crotti said:
Again on the "Globals" problem.
Since I also have an option parser, to avoid repetition and other
annonying things this approach

namespace GLOBALS
{
int num_landmarks;
int trace_length;
int history_size;
int distribution_size;
Environment *environment;
ostream *out;

is no longer good.
I need a class which stores a map where for example I keep a mapping
like

conf["num_landmarks"] = 3;
and so on.

So how do I make a class for only one object without using the annoying
singleton.
I actually don't care that it could be called more times (which won't).

Should I define the class (as extern??) in the header file and in the
.cpp allocate an object of it?

Ok I thought something like
--8<---------------cut here---------------start------------->8---
class Globals
{
private:
std::map<string, string> config;

public:
Globals();
string operator[](string& idx) { return config[idx]; }

string& operator[](string const& idx) { return config[idx]; }

(returns a reference and takes a reference to const).
};

extern Globals CONFIG;

Why do you really need a class? Why can't you simply do

extern std::map<std::string,std::string> GLOBALS;

?
--8<---------------cut here---------------end--------------->8---

in the header would work, but the operator[] doesn't work as I thought.
How do I pass a reference to a string to it?
I would like to be able to do

CONFIG["variable"] = 10;

for example, but I guess that's not casted to string reference in C++...

V
 
A

Andrea Crotti

Victor Bazarov said:
string& operator[](string const& idx) { return config[idx]; }

(returns a reference and takes a reference to const).

Ah ok I see, but why return the reference to the string also?
Why do you really need a class? Why can't you simply do

extern std::map<std::string,std::string> GLOBALS;

?

Well it would also work, but with a class for example I can initialize
the values from the configuration file directly in the constructor of
the class...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,119
Latest member
IrmaNorcro
Top