user2079828
user2079828

Reputation: 655

C++ static , extern uses with global data

I'm new to C++ and OOP in general and have been trying to learn efficient or 'correct' ways to do things, but am still having trouble.

I'm creating a DataStore class that holds data for other classes/objects. There will only ever be one instance/object of this class; however, there doesn't really need to be an object/instance since it's global data, right. In this case I feel like it's just a way to provide scope. So, I want to directly change the class members instead of passing around the object. I have read about static and _extern, but I can't decide if either would be viable, or if anything else would be better.

Right now I'm passing the one created object around to change it's data, but I would rather the class be accessed as 'itself' instead of by 'an instance of itself' while still retaining the idea of it being an object.

Upvotes: 4

Views: 1225

Answers (4)

zmbq
zmbq

Reputation: 39079

EDIT: In a comment OP explained the data store will be read by code running in multiple threads, and updated by code in one thread. My previous answer no longer applies. Here's a better answer.

Don't use a global variable to hold the store's instance. This will open the door for many subtle bugs that can haunt you for a long while. You should give your reading threads read-only access to the store. Your writing thread should get read-write access.

Make sure your read methods in the data store are properly marked as const. Then create a single instance of the data store, and put a pointer to it in a const global variable. Your writing thread should have another mechanism of getting a non-const pointer (add a GetInstance public static method, as suggested by @Mats).

My previous answer: If you're certain there will always be just one data store instance, don't pass it around.

Global variables are frowned upon, and some languages (Java and C#) outlawed them altogether. So in C# and Java you use static class members instead, which are practically the same thing (with exactly the same problems).

If you can put your single instance in a a const global variable, you should be fine.

If you're doing any kind of multithreading, you'll need to make sure your store is thread-safe, or else really bad things will happen.

Upvotes: 1

4pie0
4pie0

Reputation: 29764

you can use a controversial Singleton pattern or you can use one of PARAMETERISE FROM ABOVE approaches described in Mark Radford (Overload Journal #57 – Oct 2003) SINGLETON - the anti-pattern! article.

PARAMETERISE FROM ABOVE approach (in his opinion) strengthen encapsulation and ease initialisation difficulties.


The classic lazy evaluated and correctly destroyed singleton:

class S
{
    public:
        static S& getInstance()
        {
            static S    instance; // Guaranteed to be destroyed.
                                  // Instantiated on first use.
            return instance;
        }
    private:
        S() {};                   // Constructor? (the {} brackets) are needed here.
        // Dont forget to declare these two. You want to make sure they
        // are unaccessable otherwise you may accidently get copies of
        // your singleton appearing.
        S(S const&);              // Don't Implement
        void operator=(S const&); // Don't implement
};

But note: this is not thread-safe.

see here for good StackOverflow post about Singletons

Upvotes: 1

yngccc
yngccc

Reputation: 5694

I do this for object that have 1 instance most of time during execution of program.

class Object {
private:
  Object();
  friend Object & GetObject();

public:
   ...
};

inline Object & GetObject() {
    static Object O;
    return O;
}

1) this is less verbose than singleton.
2) this avoid pitfall of global object, such as undefined initialization order.

Upvotes: 1

Mats Petersson
Mats Petersson

Reputation: 129524

Typically, this sort of problem (where you need one, but only ever one - and you are SURE you never ever need more), is solved by using a "singleton" pattern.

class Singleton
{
  public:
    static Singleton* getInstance() 
    { 
       if (!instance) instance = new Singleton(); 
       return instance;
    }

    int getStuff() { return stuff; }


  private:
    Singleton() { stuff = 42; }
    static Singleton *instance;
    int stuff; 
};

then in some suitiable .cpp file>

static Singleton *instance;

Or use a global variable directly:

class Something
{
 public:
   Something() { stuff = 42; }

   int getStuff() { return stuff; }

 private:
   int stuff; 
}

extern Something global_something;    // Make sure everyone can find it. 

In ONE .cpp file:

Something global_something; 

Since BOTH of these are essentially a global variable solution, I expect someone disliking global variables will downvote it, but if you don't want to pass around your class object everywhere, a global variable is not a terrible idea. You just have to be aware that global variables are not necessarily a great idea as a solution in general. It can be hard to follow what is going on, and it certainly gets messy if you suddenly need more than one (because you decided to change the code to support two different storages, or whatever) - but this applies to a singleton too.

Upvotes: 4

Related Questions