Steven
Steven

Reputation: 13995

C++ best way to have a persistent object?

I am learning C++ and I am trying to use my knowledge of programming other languages to understand C++, which appears to be confusing me a lot. I am working on a basic socket program and trying to figure out the best way to handle creation of the socket class so I can read/write and only connect once.

In my other languages I would create a static object class that would allow me to reference it, if it wasn't created I would create the socket and connect. If it was created I would just return it for referencing.

But a class can't be a static class (at least that's what I've read) so I fall back on the next option I know which is Singleton.

So I ended up with something like

class Socket{
   static Socket* socket;
public:
   Socket& Get()
   {
      if (!socket) socket = new Socket;
      return *socket;
   }
};

And I would have my starting/connecting stuff in the constructor. But is this how it is suppose to be done? There seems to be a lot of conflicting stuff on the internet. For example use people use mutex, and some people use templates.

Which way would be best for something like a socket wrapping class?

Upvotes: 7

Views: 4620

Answers (3)

Martin J.
Martin J.

Reputation: 5118

Try this:

class Socket{
public:
   static Socket& Get()
   {
      static Socket* socket = new Socket;
      return *socket;
   }
};

Or even:

class Socket{
public:
   static Socket& Get()
   {
      static Socket socket;
      return socket;
   }
};

Having the static singleton socket instance declared inside the accessor prevents initialization order "conflicts" with other static variables (see here). Also, C++11 guarantees that the static local variable are initialized in a thread-safe manner (see here).

I should also point out that singleton use is relatively controversial, see this question for more details. Personally, I recommend only using singletons for read-only structures with few dependencies, whose lifetime is that of the process (i.e. no deinitialization).

Upvotes: 3

bames53
bames53

Reputation: 88225

Static classes and singletons are just different ways to have global variables and functions. Global variables are generally a bad idea. If you want a socket shared by many different parts of the system then you should create a socket locally somewhere (e.g., in main()) and then just pass it around to the components that need to share it.

If you insist on having a global variable, then I'd probably just stick to the simplest method: declare and use a global variable, not a singleton or a static class or anything like that.

Below are examples of each of these ways of making global variables and functions.


Static Class

A 'static class' is a class whose members are accessed without an instance object.

C++ classes can have all static members, though there's no way to declare a class such that non-static members are prohibited.

class StaticClass {
public:
  static Socket aStaticDataMember;
  static void aStaticFunction() {}
}

Socket StaticClass::aStaticDataMember = Socket(...);

int main() {
    StaticClass::aStaticFunction();
    StaticClass::aStaticDataMember.doWhatever();
}

Global variables and functions

// in a header
extern Socket globalVariable;
void globalFunction();

// in a cpp file
Socket globalVariable;
void globalFunction() {}

int main() {
  globalVariable.doWhatever();
  globalFunction();
}

Singleton

There are lots of different ways to do singletons in C++, but here's one way:

class SingletonClass {
public:
  void doWhatever() {}
private:
  // ... private members to implement singleton.
  // If you define any constructors they should be private

  friend SingletonClass &getSingletonClass() {
    static SingletonClass singleton; // thread safe in C++11
    return singleton;
  }
}

int main() {
  getSingletonClass().doWhatever();
}

Here's an example of not using global variables:

class ComponentAThatUsesASocket {
private:
  Socket &socket;
public:
  ComponentAThatUsesASocket(Socket &s) : socket(s) {}

  void foo() {
    socket.doWhatever();
  }
}

int main() {
  Socket socket;

  ComponentAThatUsesASocket componentA(socket);
  componentA.doWhatever();

  ComponentB componentB(socket);
  componentB.doWhatever();
}

Upvotes: 3

murrekatt
murrekatt

Reputation: 6129

It's slightly unclear what you really want to achieve, but in general you do not want/need to have static or singletons. Singletons are usually seen as bad. Most likely what you want to do could be better with another approach.

Please share what your goal is to build and it's easier to provide you with better guidance.

I think the term "persistent object" is unclear here what you really mean. Is that accessible from anywhere? Or maybe available throughout the whole program execution? If it's the former it's likely a singleton/monostate pattern. If it's the latter it could be something else, like passing an object around to all places needing it. Take a look at dependency injection which is a good pattern to be aware of to decouple and build testable code.

Upvotes: 1

Related Questions