Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411415 Posts in 69361 Topics- by 58415 Members - Latest Member: sophi_26

April 16, 2024, 03:13:28 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Global variables in a C++ project
Pages: [1] 2 3
Print
Author Topic: Global variables in a C++ project  (Read 5340 times)
Orz
Level 1
*


"When nothing is done, nothing is left undone."


View Profile WWW
« on: August 29, 2013, 07:35:51 AM »

I have a handful of functions and variables in my project that I'd like to make global.  Right now they are in a utility class, so I have to keep typing out "global::randomFloat()" and so forth.  There are a couple of strategies for putting globals in a C++ project so they're accessible to any file, and I wondered what other folks were using.
Logged
kamac
Level 10
*****


Notoriously edits his posts


View Profile
« Reply #1 on: August 29, 2013, 08:10:51 AM »

Uhm. Do you simply want to share your utility class between files, so that it's accessible from anywhere?

The only way to do that is to have a .h file, and an optional .cpp file to it.

Example, utility.h:

Code:
#ifndef MYUTILITY_H
#define MYUTILITY_H

class utility
{
    public:
    void someFunc();
};
#endif

utility.cpp:

Code:
#include "utility.h"

void utility::someFunc()
{
    // do something
}

Then just include utility.h from anywhere.

Or is that not what you wanted?
Logged

zacaj
Level 3
***


void main()


View Profile WWW
« Reply #2 on: August 29, 2013, 08:46:20 AM »

I usually just do extern in a header and then just declare them in some random source file
Logged

My twitter: @zacaj_

Quote from: mcc
Well let's just take a look at this "getting started" page and see--
Quote
Download and install cmake
Noooooooo
Eigen
Level 10
*****


Brobdingnagian ding dong


View Profile WWW
« Reply #3 on: August 29, 2013, 09:44:57 AM »

What kind of global variables are these? First of all, do you really need them? If you do and if they are each specific to one feature of the game I would divide them up into singletons along with whatever functionality you might have relating to them.
Logged

Orz
Level 1
*


"When nothing is done, nothing is left undone."


View Profile WWW
« Reply #4 on: August 29, 2013, 10:28:55 AM »

I usually just do extern in a header and then just declare them in some random source file

I will probably do that.  It really is just because I'm anal about having to type out "global::" every time.
Logged
Kekskiller
Guest
« Reply #5 on: August 29, 2013, 12:04:46 PM »

Why don't you just put them into a namespace with no wrapper class so you can use the namespace in the files were you need them (no "global::"). And if you really want to have the constructor of the utility singleton you can put it there, too, and access the vars like they were in the class (same namespace).
« Last Edit: August 29, 2013, 12:21:24 PM by Kekskiller » Logged
Eigen
Level 10
*****


Brobdingnagian ding dong


View Profile WWW
« Reply #6 on: August 29, 2013, 12:16:39 PM »

Again, what kind of variables are these, what do you use them for and do you really need to use them in such a way?
Logged

Orz
Level 1
*


"When nothing is done, nothing is left undone."


View Profile WWW
« Reply #7 on: August 29, 2013, 12:59:23 PM »

do you really need to use them in such a way?

What is this, Stack Overflow?

Why don't you just put them into a namespace with no wrapper class so you can use the namespace in the files were you need them (no "global::"). And if you really want to have the constructor of the utility singleton you can put it there, too, and access the vars like they were in the class (same namespace).

Thanks, that might work too.  I'll try a couple methods and keep the one which is least annoying.
Logged
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #8 on: August 29, 2013, 03:45:08 PM »

I write namespace modules.  The art of the module (well known to C programmers) seems to be lost on a lot of C++ developers, possibly because they have drunk too deeply of the OOP Kool-aid.

Since your example mentioned random numbers, here's a simple module that I use for my own:

Code:
// Pseudo-random number generator

#ifndef RANDOM_H
#define RANDOM_H

namespace Random
{
    // Traits type for the enumeration random.
    template <typename>
    struct Traits;

    // Seed the generator.
    void seed(unsigned n);

    // Get a new value.
    unsigned get();

    // Get a new value within a certain range.
    int get_in_range(int min, int max);

    // Get a random value for an enumeration.
    template <typename Type>
    Type get_enum();

    // Get a random enumeration value within a certain range.
    template <typename Type>
    Type get_enum_in_range(Type min, Type max);
}

// Inline functions and templates.
template <typename Type>
inline
Type Random::get_enum()
{
    return static_cast<Type>(get_in_range(Traits<Type>::min, Traits<Type>::max));
}

template <typename Type>
inline
Type Random::get_enum_in_range(Type min, Type max)
{
    return static_cast<Type>(get_in_range(min, max));
}

// Macros.
// Macros for conveniently declaring and defining enum traits.
#define DECLARE_RANDOM_ENUM_TRAITS(Type, minimum, maximum) \
namespace Random \
{ \
    template <> \
    struct Traits<Type> \
    { \
        static \
        const Type min = minimum; \
        static \
        const Type max = maximum; \
    }; \
}

#define DEFINE_RANDOM_ENUM_TRAITS(Type) \
const Type Random::Traits<Type>::min; \
const Type Random::Traits<Type>::max;

#endif

Code:
// Pseudo-random number generator

#include "random.h"
#include <cassert>
#include <inttypes.h> // Not standard as of C++98.

using namespace Random;

namespace
{
    // State values.
    uint32_t seed_low;
    uint32_t seed_high;
}

void Random::seed(unsigned n)
{
    seed_low = n;
    seed_high = ~n;
    get();
}

unsigned Random::get()
{
    seed_high = (seed_high << sizeof(unsigned) * 4) + (seed_high >> sizeof(unsigned) * 4);
    seed_high += seed_low;
    seed_low += seed_high;

    return seed_high;
}

int Random::get_in_range(int min, int max)
{
    assert(min <= max);

    int value = get() % (max - min + 1);

    return value + min;
}

The key to the whole thing is the unnamed namespace, which contains data local to the translation unit.  This allows you to keep "global" variables while still controlling access to them through the functions in the external namespace.
Logged



What would John Carmack do?
Eigen
Level 10
*****


Brobdingnagian ding dong


View Profile WWW
« Reply #9 on: August 29, 2013, 11:32:56 PM »

do you really need to use them in such a way?

What is this, Stack Overflow?

With that attitude no one should be interested in helping you. I'm not, not anymore.
Logged

InfiniteStateMachine
Level 10
*****



View Profile
« Reply #10 on: August 30, 2013, 07:37:26 AM »

I write namespace modules.  The art of the module (well known to C programmers) seems to be lost on a lot of C++ developers, possibly because they have drunk too deeply of the OOP Kool-aid.

Since your example mentioned random numbers, here's a simple module that I use for my own:

Code:
// Pseudo-random number generator

#ifndef RANDOM_H
#define RANDOM_H

namespace Random
{
    // Traits type for the enumeration random.
    template <typename>
    struct Traits;

    // Seed the generator.
    void seed(unsigned n);

    // Get a new value.
    unsigned get();

    // Get a new value within a certain range.
    int get_in_range(int min, int max);

    // Get a random value for an enumeration.
    template <typename Type>
    Type get_enum();

    // Get a random enumeration value within a certain range.
    template <typename Type>
    Type get_enum_in_range(Type min, Type max);
}

// Inline functions and templates.
template <typename Type>
inline
Type Random::get_enum()
{
    return static_cast<Type>(get_in_range(Traits<Type>::min, Traits<Type>::max));
}

template <typename Type>
inline
Type Random::get_enum_in_range(Type min, Type max)
{
    return static_cast<Type>(get_in_range(min, max));
}

// Macros.
// Macros for conveniently declaring and defining enum traits.
#define DECLARE_RANDOM_ENUM_TRAITS(Type, minimum, maximum) \
namespace Random \
{ \
    template <> \
    struct Traits<Type> \
    { \
        static \
        const Type min = minimum; \
        static \
        const Type max = maximum; \
    }; \
}

#define DEFINE_RANDOM_ENUM_TRAITS(Type) \
const Type Random::Traits<Type>::min; \
const Type Random::Traits<Type>::max;

#endif

Code:
// Pseudo-random number generator

#include "random.h"
#include <cassert>
#include <inttypes.h> // Not standard as of C++98.

using namespace Random;

namespace
{
    // State values.
    uint32_t seed_low;
    uint32_t seed_high;
}

void Random::seed(unsigned n)
{
    seed_low = n;
    seed_high = ~n;
    get();
}

unsigned Random::get()
{
    seed_high = (seed_high << sizeof(unsigned) * 4) + (seed_high >> sizeof(unsigned) * 4);
    seed_high += seed_low;
    seed_low += seed_high;

    return seed_high;
}

int Random::get_in_range(int min, int max)
{
    assert(min <= max);

    int value = get() % (max - min + 1);

    return value + min;
}

The key to the whole thing is the unnamed namespace, which contains data local to the translation unit.  This allows you to keep "global" variables while still controlling access to them through the functions in the external namespace.

I remember you posting about this before and I really took a shining to it since then. Thanks for sharing that  Smiley
Logged

Orz
Level 1
*


"When nothing is done, nothing is left undone."


View Profile WWW
« Reply #11 on: August 31, 2013, 01:08:29 AM »

I write namespace modules.  The art of the module (well known to C programmers) seems to be lost on a lot of C++ developers, possibly because they have drunk too deeply of the OOP Kool-aid.

That is a great trick.  I was doing something like that before, but only in single-file programs...I never tried to include it as a header.  I'm quite fond of OOP for games, but I had to be dragged in kicking and screaming.
Logged
Klaim
Level 10
*****



View Profile WWW
« Reply #12 on: August 31, 2013, 03:45:54 AM »

Stop coding right now and go learn how the compilation process works. I'm serious. You will be baffled regularly by code you'll see around if you don't and ask such strange questions again. That's my first and last advice as your stackoverflow remark also makes me think it's not worth loosing more of my time.
Logged

Kekskiller
Guest
« Reply #13 on: August 31, 2013, 04:23:34 AM »

This thread is a good example for why humans will never stop waging wars against each other, figuratively speaking.
Logged
darkhog
Level 7
**


Dragon Agent


View Profile
« Reply #14 on: August 31, 2013, 12:02:40 PM »

Dunno about c==, but in Java/C# I'm using static classes with static members for this. Again, dunno if c++ has thing like that.

Declaration:

Code:
public static Globals{
public static string HerosName;
public static string HerosLifeCount;
//...
}

Then when I want to change/get value, I'm doing thing like:

Code:
Globals.HerosName = "The Savior of The Universe"
Logged


Be a computer virus!


I cannot C well, so I stick with simpler languages.

There are no impossible things, there is only lack of skill.
motorherp
Level 3
***



View Profile
« Reply #15 on: September 02, 2013, 01:49:46 AM »

Since I've seen it suggested a couple times here already I just want to add that Singletons are for specifically enforcing that a class can only ever be instantiated once.  Singletons are not a good solution for solving global access issues.  I'm always seeing people suggest singletons for solving these sorts of problems .... stop it, its wrong  Beg.
Logged
powly
Level 4
****



View Profile WWW
« Reply #16 on: September 02, 2013, 03:42:52 AM »

Wtf guys, he just wants to skip writing a few letters Smiley

Code:
#define randomFloat(a) global::randomFloat(a)
Logged
darkhog
Level 7
**


Dragon Agent


View Profile
« Reply #17 on: September 02, 2013, 03:48:54 AM »

Since I've seen it suggested a couple times here already I just want to add that Singletons are for specifically enforcing that a class can only ever be instantiated once.  Singletons are not a good solution for solving global access issues.  I'm always seeing people suggest singletons for solving these sorts of problems .... stop it, its wrong  Beg.

Can you explain why it's wrong? Seriously, I can't see issue there with it - it works, it doesn't leak memory, doesn't crash software...
Logged


Be a computer virus!


I cannot C well, so I stick with simpler languages.

There are no impossible things, there is only lack of skill.
motorherp
Level 3
***



View Profile
« Reply #18 on: September 02, 2013, 04:24:03 AM »

Since I've seen it suggested a couple times here already I just want to add that Singletons are for specifically enforcing that a class can only ever be instantiated once.  Singletons are not a good solution for solving global access issues.  I'm always seeing people suggest singletons for solving these sorts of problems .... stop it, its wrong  Beg.

Can you explain why it's wrong? Seriously, I can't see issue there with it - it works, it doesn't leak memory, doesn't crash software...

Discounting the instantiation restriction, singletons are really little more than thinly veiled globals anyway, they dont in any way solve any of the issues associated with global state.  Many people use (or advice use of) singletons not because they want to restrict instantiation but simply because they want the simplicity of global access but they've heard that globals are bad.  If you're using singletons in this way you're not actualy solving anything, but you're placing additional restrictions on your project that likely aren't necessary and could be problematic in the future.  Stop lying to yourself and just use a global, or if you are concerned about global state then use dependancy injection or a factory pattern.  Singletons are only appropriate in the case were you really do need to restrict instantiation to one object instance.
Logged
Daid
Level 3
***



View Profile
« Reply #19 on: September 02, 2013, 04:56:16 AM »

Since I've seen it suggested a couple times here already I just want to add that Singletons are for specifically enforcing that a class can only ever be instantiated once.  Singletons are not a good solution for solving global access issues.  I'm always seeing people suggest singletons for solving these sorts of problems .... stop it, its wrong  Beg.

Can you explain why it's wrong? Seriously, I can't see issue there with it - it works, it doesn't leak memory, doesn't crash software...
Same for using tape to keep a painting to the wall. It works, but tape was not intended for that use. Same for singletons.

However, I think singletons are the most overjust abused pattern there is. Usually things do not need to be a singleton. And who-ever says that globals are always bad just needs to be shot.

Now, I do not recommend naming something "Global", not a namespace or static class. Your global state clearly belongs to something. "Random::currentSeed", "PlayerState::name" is better then "Global::randomSeed" "Global::PlayerName"
Logged

Software engineer by trade. Game development by hobby.
The Tribute Of Legends Devlog Co-op zelda.
EmptyEpsilon Free Co-op multiplayer spaceship simulator
Pages: [1] 2 3
Print
Jump to:  

Theme orange-lt created by panic