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?
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.
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();
}
// in a header
extern Socket globalVariable;
void globalFunction();
// in a cpp file
Socket globalVariable;
void globalFunction() {}
int main() {
globalVariable.doWhatever();
globalFunction();
}
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();
}
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With