4

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.

user2079828
  • 645
  • 1
  • 8
  • 31

4 Answers4

4

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.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
1

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.

zmbq
  • 38,013
  • 14
  • 101
  • 171
  • Put the instance in a global variable? – user2079828 Jul 05 '13 at 19:55
  • Don't use global variables! [Read This](http://stackoverflow.com/questions/484635/are-global-variables-bad) – taylorc93 Jul 05 '13 at 19:57
  • Yes, put the instance in a global variable. Make it a const global variable if possible. People will tell you it's bad, but in some cases it's OK. I'll add a calrification. – zmbq Jul 05 '13 at 20:01
  • No const because the data in the instance will be updated every 20ms, and there will be at least 2 threads running. – user2079828 Jul 05 '13 at 20:05
  • It is part of a much larger project. Members of the store 'should' only be changed by one of them though. Every other thread would just be accessing the data. – user2079828 Jul 05 '13 at 20:13
  • OK, this is a different matter, then. I don't think a simple global variable will do, I'll revise my answer. – zmbq Jul 05 '13 at 20:14
  • Don't you need something like mutex, even though there is only one writing thread and the reading threads can't modify the data? E.g., What if the reading was done in the middle of writing? – starriet Sep 02 '22 at 16:29
1

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

Community
  • 1
  • 1
4pie0
  • 29,204
  • 9
  • 82
  • 118
1

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.

yngccc
  • 5,594
  • 2
  • 23
  • 33