Singleton objects with mutable members - c++

EDIT: See GWW's answer, the problem was simply making an illicit copy with C::Instance(). And I was wrong, the error does not depend on mutable.
Are static methods incompatible with mutable methods? Here's a simplified version of my code:
c.h:
class C
{
public:
static C& Instance();
private:
C();
mutable QMutex _mutex;
};
c.cpp:
C& C::Instance()
{
static C instance;
return instance;
}
C c = C::Instance();
Then the error I'm getting (gcc 4.2) is
error: 'QMutex::QMutex(const QMutex&)' is private within this context
synthesized method 'C::C(const C&)' first required here //at C::Instance()
If I remove the 'mutable' keyword this error goes away, but then of course I can't make the methods that lock/unlock _mutex const. Writing my own copy ctor doesn't change anything. Anyone know how to solve this? NB this looks similar to this post but that's objective-C and there was just too much code in there that didn't seem relevant to the question.
EDIT: Just realized that the problem, obviously, is that QMutex's copy ctor is private. But I don't understand why 'mutable' should make a difference here, i.e. why it induces a copy.

You are trying to copy your singleton and it fails because you have declared a copy constructor private. It has absolutely nothing to do with mutable members.

Related

Static initialization with private constructor

In a class I have a static member that represents the singleton instance of that class:
class A {
public:
static const std::shared_ptr<A> INSTANCE;
private:
A();
};
In order to prevent more instances I made the constructor private. Now I have trouble to initialize the static var, because the initializer cannot access a private member. Here's the code I use in the .cpp file:
const std::shared_ptr<A> A::INSTANCE = std::make_shared<A>();
A factory method wouldn't help either, as it would have to be public as well. What else can I do to make this work? Note: I'd like to avoid the typical static get() method if possible.
You can't use make_shared, but you can just create the instance directly:
const std::shared_ptr<A> A::INSTANCE { new A };
The initialization of a static member is unrelated to the constructor, so the global statement is indeed the right way to go. Is it not working for you?
EDIT: I just realized you're trying to avoid using a singleton access method for some reason. Sounds suspiciously like the Borg pattern. :) Unrelated to you r specific question but I'd advise you to reconsider.

Explicitly initialize member which does not have a default constructor

I´m trying to instantiate an object which has no default constructor so it can be referenced from any methods inside the class. I declared it in my header file, but the compiler says that the constructor for the class creating it must explicitly initialize the member, and I can´t figure out how to do that.
Really appreciate your answers, thank you in advance!
The snippet:
MyClass.h
include "MyOtherClass.h"
class myClass {
private:
MyOtherClass myObject;
public:
MyClass();
~MyClass();
void myMethod();
}
MyClass.cpp
include "MyClass.h"
MyClass::MyClass() {
MyOtherClass myObject (60);
myObject.doSomething();
}
MyClass::myMethod() {
myObject.doSomething();
}
MyOtherClass.h
class MyOtherClass {
private:
int aNumber;
public:
MyOtherClass (int someNumber);
~MyOtherClass();
void doSomething();
}
MyOtherClass.cpp
include "MyOtherClass.h"
MyOtherClass::MyOtherClass (int someNumber) {
aNumber = someNumber;
}
void MyOtherClass::doSomething () {
std::cout << aNumber;
}
You are almost there. When you create an object in C++, by default it runs the default constructor on all of its objects. You can tell the language which constructor to use by this:
MyClass::MyClass() : myObject(60){
myObject.doSomething();
}
That way it doesn't try to find the default constructor and calls which one you want.
You need to initialize the myObject member in the constructor initialization list:
MyClass::MyClass() : myObject(60) {
myObject.doSomething();
}
Before you enter the body of the constructor all member variables must be initialized. If you don't specify the member in the constructor initialization list the members will be default constructed. As MyOtherClass does not have a default constructor the compiler gives up.
Note that this line:
MyOtherClass myObject (60);
in your constructor is actually creating a local variable that is shadowing your myObject member variable. That is probably not what you intended. Some compilers allow you turn on warnings for that.
There are two errors
Your code MyOtherClass myObject(60); is not initializing the member of the class, but it's instead declaring a local variable named myObject that will hide the member inside the constructor. To initialize a member object that doesn't have a default constructor you should use member initialization lists instead.
You are trying to learn C++ by experimenting with a compiler.
This second error is the most serious error and if not corrected is going to take you to a terribly painful path; the only way to learn C++ is by getting one or two good books and read them cover to cover. Experimenting with C++ doesn't work well.
No matter how smart you are there's no way you can guess correctly with C++, and in a sense being smart is even dangerous (because you may be tempted to skip over something "you understood already"): the reason is that it happens in quite a few places that the correct C++ way is illogical and consequence of historical evolution of the language.
In many places C++ is the way it is because of history and not because it makes sense, and no matter how smart you are there's no way you can deduce history... history must be studied.
MyClass::MyClass(): myObject (60){
myObject.doSomething();
}
Initialization of the data member ends before constructor function body.in the function body you just assign

How to prevent construction of a class's object?

I can't find the answer anywhere. It can be done by using condition and throwing exception but is there any other way to do so?
It isn't clear why you would want a class that cannot be constructed under any circumstances, but you could make all constructors private and provide no implementation for them. This will prevent construction at compile time.
In C++11 you can use delete for all the constructors:
class A
{
public: // or private, doesn't matter.
A()=delete;
A(const A&)=delete;
A(A&&)=delete;
};
Well, this is a bit of an awful hack but quite frankly any C++ application which needs a way to define an unconstructable object is probably already an awful hack!
class la
{
public:
virtual void oh_no_you_dont() = 0;
};
int main()
{
la an_instance;
return 0;
}
And under GCC, I get the following:
test.cpp: In function ‘int main()’:
test.cpp:9: error: cannot declare variable ‘an_instance’ to be of abstract type ‘la’
test.cpp:2: note: because the following virtual functions are pure within ‘la’:
test.cpp:4: note: virtual void la::oh_no_you_dont()
You can make all constructors private. This way it's impossible to create an instance of the class. You can then supply one or more static factory methods for creating the class, and by this make the users use only factory methods.
Do you want your class to prevent from being constructed?
Here is a solution with an old C++ standard e.g. C++03 and older
class A {
private:
A();
A(const A&)
A(A&&);
~A()
};
Here is a solution using the latest C++ standard e.g. C++11, C++14, C++17, C++20
class A
{
A()=delete;
A(const A&)=delete;
A(A&&)=delete;
};
or even
class A final {
~A() = delete;
}
final means that a class cannot be inherited from.
delete for a destructor means that you can not destruct a class
Prohibiting a destructor blocks you from constructing an object also.
Why do we want to prohibit objects from being constructed/destructed?
A very common use case is that a developer wants to create a "static" class in C++.
"static" class in C++ means a class with only static methods.
This pattern is also know as an "util" class.
Instead of defining a class many people advice to use a canonical namespace that contains static functions for this purpose.

Copy constructor called on singleton class

I have the following problem. I have a singleton with a getInstance member function that returns an instance. I call this somewhere in code and for some reason VC tries to call the copy constructor. Why is this? How do I fix this?
The header:
class FileSystemEntryCollection {
public:
static FileSystemEntryCollection &getInstance();
private:
FileSystemEntryCollection();
FileSystemEntryCollection(FileSystemEntryCollection const&);
void operator=(FileSystemEntryCollection const&);
}
Source file:
FileSystemEntryCollection &FileSystemEntryCollection::getInstance() {
static FileSystemEntryCollection instance = FileSystemEntryCollection();
return instance;
}
The following line calls the copy constructor:
auto collection = FileSystemEntryCollection::getInstance();
I've tried to leave in the relevant code, let me know if something else is needed.
auto collection = FileSystemEntryCollection::getInstance();
needs to be:
auto& collection = FileSystemEntryCollection::getInstance();
^
auto on its own is never a reference type.
With a different compiler you'll get the same error for the initialization of instance.
static FileSystemEntryCollection instance = FileSystemEntryCollection();
The = here calls for copy construction: formally, the compiler creates a temporary (FileSystemEntryCollection()), and copies that into instance. However, in this situation, compilers are allowed to skip the copy construction and construct the object directly in place. That's what your compiler is doing. But compilers aren't required to do this.
Better:
static FileSystemEntryCollection instance;
which uses the default constructor to create instance.
It calls the copy constructor once inside the source file which constructs the static singleton object.

Single class instance C++

Is it possible to create a class which could be constructed just one time? If you would try to create an other instance of it, a compile-time error should occure.
Instantiation is dynamic, at run time. Compilation errors are at compile time. So the answer is no, it's not possible to get a compilation error on any second instantiation.
You can however use a singleton, but do consider very carefully whether it's really needed.
The classes with only one instances are called singleton classess,
There are many ways to perform that. The simplest is shown below
class MySingleton
{
public:
static MySingleton& Instance()
{
static MySingleton singleton;
return singleton;
}
// Other non-static member functions
private:
MySingleton() {}; // Private constructor
MySingleton(const MySingleton&); // Prevent copy-construction
MySingleton& operator=(const MySingleton&); // Prevent assignment
};
Why compile error? You just need to implement Singleton design pattern, I think.
Look here