I have a Singleton class here designed to be inherited by classes wanting to use it. But I have a question about something the compiler is allowing and I don’t understand why:
template<class DerivedT>
class Singleton {
static DerivedT*& internalPointer() {
static DerivedT* object(nullptr);
return object;
}
void reassignIf(Singleton* instance) {
auto& object(internalPointer());
if (object == static_cast<DerivedT*>(instance)) {
object = static_cast<DerivedT*>(this);
}
}
Singleton(Singleton const& other); // = delete
Singleton& operator=(Singleton const& other); // = delete
public:
static DerivedT* instance() { return internalPointer(); }
protected:
Singleton() { reassignIf(nullptr); }
Singleton(Singleton&& other) { reassignIf(&other); }
~Singleton() {
auto& object(internalPointer());
if (object == static_cast<DerivedT*>(this)) {
object = nullptr;
}
}
Singleton& operator=(Singleton&& other) { reassignIf(&other); return *this; }
};
class SingletonMock: Singleton<SingletonMock> {
public:
using Singleton<SingletonMock>::instance;
SingletonMock() : Singleton<SingletonMock>() { }
};
int main() {
SingletonMock x;
SingletonMock const y; // why is this line allowed?
}
Why is the bottom line allowed? The Singleton base class has a static member function called internalPointer that has a static DerivedT*. This should become SingletonMock*, but it’s allowing a const SingletonMock to be assigned to that variable.
EDIT:
I think I understand why it’s working now from the comments. However, specifically it’s allowing me to do this:
SingletonMock const y;
SingletonMock* yPtr(SingletonMock::instance());
How can I stop something like that from being allowed?
I think the question is: Why does the compiler allow me to declare a
const Singleton? I’m assuming you are wondering how the compiler can let you create aconst Singletonwhen you only want to have pointers to a non-constSingleton. If you declare a const instance of a class that has a constructor, it still needs to be constructed. In that constructor, it is not const. Once the constructor finishes, it can only be accessed as const, but that doesn’t apply while it’s being constructed. Otherwise, you couldn’t have const instances of any class.