I have counter.h:
static int count() {
static int counter = 0; // called anew in each translation unit
return ++counter;
}
and Singleton.h:
class Singleton
{
public:
Singleton(const Singleton& other) = delete;
Singleton& operator = (const Singleton& other) = delete;
static Singleton& instance()
{
static Singleton ret; // called only once
return ret;
}
private:
Singleton() { std::cout << "call\n"; }
};
and foo.cpp:
void foo()
{
count();
auto& db = Singleton::instance();
}
zoo.cpp:
void zoo()
{
count();
auto& db = Singleton::instance();
}
main.cpp:
int main()
{
foo();
zoo();
return 0;
}
Why the line static int counter = 0; called twice but the line static Singleton ret; only once?
The function int count() is declared static, as such it gets internal linkage, meaning there's a separate copy of the function created in each translation unit in which it is used.
If you want a single count() function in the application, don't declare it static so that it gets external linkage (and move the definition to a .cpp file), or simply declare it inline.
inline int count() {
static int counter = 0;
return counter;
}
This is different from a static class member. Class members, including static ones, get the same linkage as the class they belong to (which in your case has external linkage).
Related
Given the singleton class
class MySingleton
{
// ...
public:
MySingleTon& instance() { /* ... */ }
};
is it possible to prevent:
int main()
{
// the following should cause some error
MySingleton& singleton = MySingleton::instance();
}
while still allowing:
int main()
{
// Only directly accessing MySingleton::instance().SomeMethod should be possible
MySingleton::instance().some_method();
}
Extra example
int main()
{
// Following two lines should error
MySingleton& singleton = MySingleton::instance();
singleton.some_method();
// Following line should NOT error
// Additionally it should be the only way to access any MySingleton method besides MySingleton::instance
MySingleton::instance().some_method();
}
The only way I know to do what you are looking for is to make instance() itself be private so code that is outside of MySingleton can't call it directly, then add a static method to MySingleton that is public and uses instance() internally as needed, eg:
class MySingleton
{
// ...
private:
MySingleton() { /* ... */ }
static MySingleton& instance() { static MySingleton inst; return inst; }
public:
static void do_method() { instance().some_method(); }
};
int main()
{
MySingleton& singleton = MySingleton::instance(); // <-- ERROR
singleton.some_method();
MySingleton::do_method(); // <-- OK
}
Is it possible to define a Meyer's singleton (like this one) with arguments?
I know it is possible with the GOF style singleton (like here),
but I can't seem to make it work with Meyer's singletons:
// ...
public:
static S& getInstance()
{
static S instance; // no way to pass arguments here ...
return instance;
}
EDIT:
I want a single Init function, and multiple getInstance.
So a typical usage is something like:
S::Init(5, 6.4);
foo(S::getInstance());
bar(S::getInstance());
You can just store the initialization parameters in statics. Example:
class S {
public:
static void Init(int i)
{
i_ = i;
initialized_ = true;
}
static S& getInstance()
{
if (!initialized_) {
throw SomeException;
}
static S instance(i_);
return instance;
}
private:
S(int) { }
static int i_;
static bool initialized_;
};
Remember to actually define the statics in the implementation (.cpp) file:
int S::i_ = 0;
bool S::initialized_ = false;
Obviously you could use Meyer singletons as well for these, but since they're built-in types and do not depend on other data, you wouldn't really gain much.
You could do something like this:
class Singleton
{
private:
static std::unique_ptr<Singleton>& getObject()
{
static std::unique_ptr<Singleton> instance;
return instance;
}
Singleton(int foo);
public:
static void Init(int foo)
{
auto& instance = getObject();
if (instance) throw std::runtime_error("aleady inited");
instance.reset(new Singleton(foo));
}
static Singleton& getInstance()
{
auto& instance = getObject();
if (!instance) throw std::runtime_error("not inited");
return *instance;
}
};
Note that this isn't thread safe and will have undefined behaviour if multiple threads call Init or a thread calls getInstance whilst another is calling Init.
If your parameters could be replaced by template arguments then you could do it this way instead:
template <int foo>
class SingletonImpl
{
private:
SingletonImpl(int f);
public:
static SingletonImpl<foo>& getInstance()
{
static SingletonImpl<foo> instance(foo);
return instance;
}
};
using Singleton = SingletonImpl<10>;
The best solution is probably to separate initialisation and construction:
class Singleton
{
private:
std::atomic<bool> initialised;
Singleton()
: initialised(false)
{
}
Singleton& instanceImpl()
{
static Singleton singleton;
return singleton;
}
public:
void Init(int foo)
{
auto& instance = instanceImpl();
if (instance.initialised) throw std::runtime_error("already inited");
instance.initialised = true;
}
Singleton& getInstance()
{
auto& instance = instanceImpl();
if (!instance.initialised) throw std::runtime_error("not inited");
return instance;
}
};
I'm new to programing and I was trying for the program which makes the class singleton..Is this the correct approach for making a class singleton??
#include <iostream>
using namespace std;
class Singleton
{
private:
static bool instanceFlag;
static Singleton *single;
public:
static Singleton* getInstance();
void method();
~Singleton()
{
instanceFlag = false;
}
};
bool Singleton::instanceFlag = false;
Singleton* Singleton::single = NULL;
Singleton* Singleton::getInstance()
{
if(! instanceFlag)
{
single = new Singleton();
instanceFlag = true;
return single;
}
else
{
return single;
}
}
void Singleton::method()
{
cout << "Method of the singleton class";
}
int main()
{
Singleton *sc1,*sc2;
sc1 = Singleton::getInstance();
sc1->method();
sc2=Singleton::getInstance();
sc2->method();
return 0;
}
Is this the correct way of making class singleton??
You are over-complicating things. Try the Scott Meyers singleton:
struct SingletonClass {
// instance() function return a reference
static SingletonClass& instance() {
// static local variable are initialized one time.
static SingletonClass inst;
// We return the instance, which is the same for every calls.
return inst;
}
private:
// Private since we don't want other class to create instances
SingletonClass() = default;
// Our class is not copiable or movable
SingletonClass(const SingletonClass&) = delete;
SingletonClass(SingletonClass&&) = delete;
SingletonClass& operator=(const SingletonClass&) = delete;
SingletonClass& operator=(SingletonClass&&) = delete;
};
You can use your class like that:
auto& myInstance = SingletonClass::instance();
Bonus: It doesn't use dynamic allocation, it's thread safe, and is much simpler.
try this solution:
class Singleton {
private:
static Singleton* instance;
Singleton() {} // must be private
public:
static Singleton* getInstance() {
if (instance == NULL)
instance = new Singleton();
return instance;
}
void method() { cout << "Method of the singleton class\n"; }
};
Singleton* Singleton::instance = NULL;
I see errors like
src/singleton.cxx:16:error: invalid use of member 'Singleton::instance' in static member function
src/singleton.cxx:28:error: from this location
src/singleton.cxx:16:error: invalid use of member 'Singleton::instance' in static member function
src/singleton.cxx:29:error: from this location
src/singleton.cxx:16:error: invalid use of member 'Singleton::instance' in static member function
src/singleton.cxx:31:error: from this location
src/singleton.cxx: In function 'int main()':
Now after making changes I get the following errors
singleton-rhel6.3.o: In function Singleton::get_instance()':
src/singleton.cxx:27: undefined reference toSingleton::instance'
#include <cstddef>
class Singleton {
private:
Singleton();
static Singleton * instance;
int m_num;
int incr_call();
public :
static Singleton * get_instance();
};
Singleton * Singleton::get_instance() {
if(instance == NULL)
instance = new Singleton();
return instance;
}
Singleton::Singleton():
m_num(0)
{
}
int Singleton::incr_call() {
return m_num++;
}
int main() {
Singleton * s = Singleton::get_instance();
return 0;
}
instance should be static since you want to be able to call it in get_instance. Also, instance should be private:
class Singleton {
public :
static Singleton * get_instance();
private:
Singleton();
static Singleton * instance;
int m_num;
int incr_call();
};
Singleton* Singleton::instance;
You should change your constructor too, to not initialize instance:
Singleton::Singleton():
m_num(0)
{ }
Because instance is static default initialization is done and it will be NULL / nullptr.
If you have to use singleton, use Meyers' one:
class Singleton {
private:
Singleton() = default;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public :
static Singleton& get_instance()
{
static Singleton instance;
return instance;
}
// Extra stuff
};
If I take this in an static object and store it in a vector in a Singleton object, can I assume the pointer points to the object during the whole lifetime of the program?
In general, you can't assume that, because order of static object creation in different translation units is unspecified. In this case it will work, because there is only single translation unit:
#include <iostream>
#include <vector>
class A
{
A() = default;
A(int x) : test(x) {}
A * const get_this(void) {return this;}
static A staticA;
public:
static A * const get_static_this(void) {return staticA.get_this();}
int test;
};
A A::staticA(100);
class Singleton
{
Singleton(A * const ptr) {ptrs_.push_back(ptr);}
std::vector<A*> ptrs_;
public:
static Singleton& getSingleton() {static Singleton singleton(A::get_static_this()); return singleton;}
void print_vec() {for(auto x : ptrs_) std::cout << x->test << std::endl;}
};
int main()
{
std::cout << "Singleton contains: ";
Singleton::getSingleton().print_vec();
return 0;
}
Output:
Singleton contains: 100
But what if A::staticA in defined in different translation unit? Will it be created before static Singleton is created? You can't be sure.