Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ best way to have a persistent object?

Tags:

c++

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?

like image 587
Steven Avatar asked Feb 16 '14 17:02

Steven


2 Answers

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();
}
like image 137
bames53 Avatar answered Oct 15 '22 06:10

bames53


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).

like image 29
Martin J. Avatar answered Oct 15 '22 05:10

Martin J.