Reputation: 123
I want to write a Meyers Singleton class using references but it does not work. I seem to still get separate instances of the class with each call to the instance accessor method even though a print suggests the constructor is only being called once. But if I write it using pointers it works fine. Can anyone explain why and how to fix the reference version? Thanks!
Pointer version that works:
X.h
class X {
public:
static X *getX(void);
void ipp();
int geti();
private:
X();
int i;
};
X.cpp
#include "X.h"
X::X()
{
printf ("X constructor\n");
i = 0;
}
X *X::getX()
{
static X the_only_X;
return &the_only_X;
}
int X::geti()
{
return (i);
}
void X::ipp()
{
i++;
}
tryit.cpp
#include <stdio.h>
#include "X.h"
int main (int ac, char *av[])
{
printf ("main\n");
X *x1 = X::getX();
x1->ipp();
printf ("i= %d\n", x1->geti());
X *x2 = X::getX(); // same X instance?
x2->ipp();
printf ("i= %d\n", x1->geti());
x1->ipp();
printf ("i= %d\n", x1->geti());
x2->ipp();
printf ("i= %d\n", x1->geti());
return (0);
}
Build and run, should get i= 1, 2, 3, 4:
g++ -Wall X.cpp tryit.cpp && ./a.out
main
X constructor
i= 1
i= 2
i= 3
i= 4
Reference version that does not work:
X.h:
class X {
public:
static X& getX(void);
void ipp();
int geti();
private:
X();
int i;
};
X.cpp:
#include "X.h"
X::X()
{
printf ("X constructor\n");
i = 0;
}
X& X::getX()
{
static X the_only_X;
return the_only_X;
}
int X::geti()
{
return (i);
}
void X::ipp()
{
i++;
}
tryit.cpp:
#include <stdio.h>
#include "X.h"
int main (int ac, char *av[])
{
printf ("main\n");
X x1 = X::getX();
x1.ipp();
printf ("i= %d\n", x1.geti());
X x2 = X::getX(); // same X instance?
x2.ipp();
printf ("i= %d\n", x1.geti());
x1.ipp();
printf ("i= %d\n", x1.geti());
x2.ipp();
printf ("i= %d\n", x1.geti());
return (0);
}
Build and run, should get i= 1, 2, 3, 4:
ecd-imac27$ g++ -Wall X.cpp tryit.cpp && ./a.out
main
X constructor
i= 1
i= 1
i= 2
i= 2
Upvotes: 0
Views: 562
Reputation: 62093
X x1 = X::getX();
is making a copy of the singleton instance. So is X x2 = X::getX();
. That means you actually have three instances of X
. Oops. How can that happen? This is supposed to be a singleton!
If a singleton class is copyable and/or moveable, then it really isn't a singleton. So enforce that by deleting the copy and move operations from your class (which are otherwise provided by the compiler by default):
class X {
public:
static X& getX(void);
void ipp();
int geti();
private:
X();
X(const X&) = delete; // Copy ctor
X(X&&) = delete; // Move ctor
X& operator=(const X&) = delete; // Copy assignment
X& operator=(X&&) = delete; // Move assignment
int i;
};
Having done this, you will find that X x1 = X::getX();
and X x2 = X::getX();
fail to compile. Good! The compiler is preventing you from making more X
instances. Fix that by using references instead:
X& x1 = X::getX();
X& x2 = X::getX();
And all works correctly:
main
X constructor
i= 1
i= 2
i= 3
i= 4
Upvotes: 3