Reputation: 13995
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
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
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.
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();
}
Upvotes: 3
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