7

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?

Steven
  • 10,974
  • 30
  • 86
  • 143
  • Since I'm also relatively new to C++ programming I'm interested in expert opinions about that question, too. I solved that kind of problem so far with static class methods that have a static instance variable declared in their method body (only initialized once upon first call as far as I know). – tiguchi Feb 16 '14 at 18:01
  • 2
    you have static member function in c++ and static member data. so you could make your function `Get` a static function. **Look at the C++ implementation of the Singleton design pattern**. – Stephane Rolland Feb 16 '14 at 18:01
  • 1
    possible duplicate of [C++ Singleton design pattern](http://stackoverflow.com/questions/1008019/c-singleton-design-pattern) – Stephane Rolland Feb 16 '14 at 18:05
  • 4
    How about creating the socket once and passing it to what needs it? – Vaughn Cato Feb 16 '14 at 18:06
  • What about concurrency and singleton creation. How does C++ behave when two threads access the singleton getter simultaneously? Is it necessary to guard the static variable with a lock? – tiguchi Feb 16 '14 at 18:12
  • 2
    This thread sums up my question pretty well. Just in this thread is people who say use singleton, and people who say don't use singleton. It seems to me that it is just a what ever floats your boat type of situation, and there is no "best way". – Steven Feb 16 '14 at 18:18
  • As with most other things there are pros and cons. In this case you could use a singleton and take the cons. Or you could see if something else fits better like what @Vaughn Cato suggested to pass around an object. These are two ways and the latter is usually the better. It's a pity that god/bad discussions trigger so much heat. Singletons do have places where they fit, but there are cons that I personally try to avoid. – murrekatt Feb 16 '14 at 18:23
  • 1
    @NobuGames You can provide a second function to indirect, and put an auto lock before. – πάντα ῥεῖ Feb 16 '14 at 18:23
  • @NobuGames Before C++11 C++ had no concept of threads and so initializing a static variable wasn't defined to be thread safe. With C++11 initializing static variables is thread safe (sometimes called 'magic statics'), no explicit locks required. – bames53 Feb 16 '14 at 18:40
  • @bames53 Thanks for clearing that up. I already assumed problems there because they also exist in badly implemented Java singletons. Also thanks to πάντα ῥεῖ for the workaround. – tiguchi Feb 16 '14 at 18:45

3 Answers3

3

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

Community
  • 1
  • 1
Martin J.
  • 4,748
  • 4
  • 21
  • 38
  • 2
    don't foget the need for deleting the allocated pointer. Look at the standard C++ implementation of the Singleton design pattern. – Stephane Rolland Feb 16 '14 at 18:03
  • If you need to deinitialize the singleton, you can provide an additional static or instance `deinit()` method on `Socket`, that frees resources. – Martin J. Feb 16 '14 at 18:09
  • but with your first example your `terminate`/`deinit` function would be very akward. – Stephane Rolland Feb 16 '14 at 18:10
  • 1
    I guess a smart pointer (unique_ptr) could work for the first case – tiguchi Feb 16 '14 at 18:14
  • @StephaneRolland: Destruction handling of a Singleton is not as easy, what behavior do you want after its' destruction ? Pick among *undefined behavior*, *null pointer returned* and *temporary resurrection*. – Matthieu M. Feb 16 '14 at 18:33
3

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();
}
bames53
  • 79,748
  • 13
  • 162
  • 229
1

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.

Community
  • 1
  • 1
murrekatt
  • 5,525
  • 4
  • 34
  • 61
  • 2
    If singletons are bad, what is good? How would you create a socket wrapping library that would allow you to reference the socket object once, and have that same object be able to be referenced throughout your application. Connecting/starting the socket connection a single time. ie static. – Steven Feb 16 '14 at 18:05
  • @Steven: you're right of course. There are places where this is not bad. My point was simply in the context of a beginner with C++ and wanting to use singletons/monostate. It depends on what you make and maybe what OP is making could be better with something else. – murrekatt Feb 16 '14 at 18:08
  • I agree, if you know what you're doing with singletons, they can be useful. I guess they can be a problem when you are trying to unit-test your code. Reverting the tested components that use a singleton to "mint condition" can be a cause of unexpected problems. – tiguchi Feb 16 '14 at 18:09
  • I am the OP. And that is what I want to make. How would you do it if you don't mind me asking. – Steven Feb 16 '14 at 18:10
  • @Steven: OK. If that is what you want to make and you know that this is a good way to approach what you want to make, then you should look at singleton/monostate implementation in C++. I am not entirely sure what you want to make so my answer was general. – murrekatt Feb 16 '14 at 18:13