What is wrong with this implementation in header file?
template <typename T>
class Singleton
{
public:
static T* getInstance()
{
if (m_instance == NULL)
{
m_instance = new T();
}
return m_instance;
}
private:
static T* m_instance;
};
I use it like this:
typedef Singleton<MyClass> MyClassSingleton;
I get linker error:
error LNK2001: unresolved external symbol "private: static class MyClass * Singleton<class MyClass>::m_instance" (?m_instance#?$Singleton#VMyClass####0PAVMyClass##A)
When I add
template <typename T> T* Singleton<T>::m_instance = NULL;
it works, but I worry on two things:
Static member should be defined in .cpp file in order to have only one instance in all compilation units, even if you include the header file into 10 source files
Pointers are being initialized to NULL by standard, why I need to explicitly initialize?
You can fix your error by adding a definition for the m_instance member after the class definition.
template<typename T>
T* Singleton<T>::m_instance = nullptr;
For class templates, it's OK to add the definition of static members within the header itself, and won't lead to ODR violations.
But, as others have suggested, it's best to change you getInstance() definition to
static T& getInstance()
{
static T instance;
return instance;
}
C++11 even guarantees that the creation of the function local static variable instance will be thread-safe.
Static members always need to be initialized exactly once, including those from template instantiations.
You can avoid this with local statics if you really like:
template <typename T>
T *Singleton<T>::getInstance() {
// Will be lazy initialized on first call (instead of startup) probably.
static T instance;
return &instance;
}
Or:
// No need to use pointers, really...
template <typename T>
T &Singleton<T>::getInstance() {
static T instance;
return instance
};
If you're really want to use a singleton, and you're really sure you want to use a templated singleton, you may want to use Scott Meyer's singleton approach:
template <typename T>
class Singleton
{
public:
static Singleton<T>& getInstance() {
static Singleton<T> theInstance;
return theInstance;
}
private:
Singleton() {}
Singleton(const Singleton<T>&);
Singleton<T>& operator=(const Singleton<T>&);
};
Pointers are being initialized to NULL by standard, why I need to
explicitly initialize?
You don't need.
template <typename T>
T* Singleton<T>::m_instance;
This will suffice as static & global variables are zero initialized by default
Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5)
before any other initialization takes place.
Others have answered how to fix the code, but your question was also about the reasoning. By way of explanation, what you are struggling with is the difference between declaration and definition. In this line:
static T* m_instance;
You are declaring that there is a name for m_instance, but you have not defined the space. The line of code you added defines the space.
Related
I'm trying to implement singleton template which could instantiate (from template argument) object of the class by ctor with some set of the parameters.
The code below looks ordinary and working.
template <typename T>
class Singleton
{
public:
template<typename... Ts>
static T &instance(Ts &&...args)
{
static T instance{std::forward<Ts>(args)...};
return instance;
}
protected:
Singleton() = default;
~Singleton() = default;
Singleton(const Singleton &) = delete;
Singleton &operator=(const Singleton &) = delete;
};
there is an interesting question:
if we are trying to get the instance using different ctors, intuitively expected that is a single instance:
// create with T with some specific parameters
Singleton<MyClass>::instance(1, nullptr, "test").dosomething();
// ....
// use such version for simpler notation
// or where the paramters are not available
Singleton<MyClass>::instance().dosomething();
In C++ template terms, obviously the instances are a different due of different instantiations of template instance() function.
if we write "old style" singleton (Meyer's version) based on member pointer to the instance, it solves the problem as the instance will be outside of template class method.
So the question is - is there some technique to keep "reference-style" singleton and keep this outside of "instance()" function to prevent different instances ? or anything else?
You can store the instance in a static member. The advantage of the meyers singleton is that initialization of the instance is thread safe just by how a local static varible works. Though the same can be achieved differently. As also the static requires the implementation to use some sort of synchronization mechanism, I do not expect too much difference in terms of performance when an explicit synchronization mechanism is used. I use std::once here.
#include <memory>
#include <mutex>
#include <iostream>
template <typename T> class Singleton {
public:
template<typename... Ts> static T& instance(Ts &&...args) {
std::call_once(once,[&](){
_instance = std::make_unique<T>(std::forward<Ts>(args)...);
});
return *_instance;
}
protected:
static std::unique_ptr<T> _instance;
static std::once_flag once;
Singleton() = default;
~Singleton() = default;
Singleton(const Singleton &) = delete;
Singleton &operator=(const Singleton &) = delete;
};
template <typename T> std::unique_ptr<T> Singleton<T>::_instance;
template <typename T> std::once_flag Singleton<T>::once;
struct T {
int value;
T(int x) : value(x) { std::cout << "hello world" << std::endl; }
T() = default;
};
int main() {
std::cout << Singleton<T>::instance(42).value;
std::cout << Singleton<T>::instance().value;
}
Live Demo (note the -pthread, without it will segfault).
std::call_once ensures that only one thread enters the function and only reach the return when _instance is initialized. Effectively it is the same as the static local.
The caveat is that Singleton<T>::instance() only compiles when T has a default constructor, otherwise it not (https://godbolt.org/z/TMdGe16re). I felt that this is beyond the question being asked here and did not include a solution. You can optionally add a instance() overload that does not call the constuctor but throws an exception when _instance is not yet initialized for the case when T cannot be default constructed.
Last and least the usual dislaimer against the singleton pattern: Don't, blablablbla blablabla blablablubb, globals are evil, blablablubb.
class TestClass
{
public:
static int testMember;
template<class T> static T* Foo()
{
//Defination....
}
}
//int TestClass::testMember; //Duplicate definition
Why can't I define a member field in .hpp while I can define member functions in .hpp?
Does it must be defined in a .cpp file?
Why can't I define a member field in .hpp
You can.
C++ doesn't care what you name your files, and doesn't care what extension the files have.
What you can't do is define the variable more than once. That would obviously violate the one definition rule.
In order to satisfy the one definition rule, you have two options:
In C++17 or later, make the variable inline.
class TestClass
{
public:
static inline int testMember;
template<class T> static T* Foo()
{
//Defination....
}
}
In any version of C++, place the definition in your code where it will be compiled exactly once.
Why ... [can I] define member functions in .hpp?
Because member functions, defined in the class, are implicitly inline. Just like your variable could be.
As Drew Dormann has mentioned, template member functions (static or not) are implicitly inline.
The same goes for class templates:
template <typename>
class TestClass
{
public:
static int testMember;
template<class T> static T* Foo()
{
//Definition....
}
};
// prior to C++17 you definition MUST be outside the class in the header
template <typename T>
int TestClass<T>::testMember{};
When using the Meyers singleton:
class Singleton
{
public:
static Singleton& instance()
{
static Singleton instance;
return instance;
}
void Hello()
{
std::cout <<"Hello!\n";
}
protected:
Singleton() = default;
~Singleton() {};
private:
Singleton(Singleton const&);
Singleton& operator=( Singleton const& );
};
You are able to call the instance as follow:
Singleton::instance().Hello();
or
Singleton& s = Singleton::instance();
s.Hello();
But I'm wondering if there is a way to block this:
Singleton::instance().instance();
How to avoid to call instance() as a method (with the .) and only support the static call with the :: ?
Is there a way to use static_assert, template enable_if or anything else?
First, I don't think this is a practical concern. Nobody is going to write Singleton::instance().instance().instance().Hello(). Or rather, if people are writing that on purpose, I think you have bigger problems. This is fine, as-is.
If you really want to prevent that, then you just have to move instance() outside of the class so it ceases to be a member function. There's nothing for you to assert or constrain, since you cannot tell if your static member function was called on an object or not (and you cannot overload a static member function with a non-static one taking the same argument list). Either you can write both Singleton::instance() and Singleton::instance().instance(), or neither.
Simplest is just:
class Singleton {
// ...
friend Singleton& make_singleton();
};
Singleton& make_singleton() {
static Singleton instance;
return instance;
}
Now it's just make_singleton().Hello(), and there's no other way to write that at all. This can be arbitrarily generalized by wrapping it in a singleton class template factory:
template <typename T>
struct SingletonFactory
static T& instance() {
static T instance;
return instance;
}
};
SingletonFactory<Singleton>::instance().Hello(); // ok
SingletonFactory<Singleton>::instance().instance().Hello(); // error
What is the best way to have a static member in a non-templated library class,
without placing the burden of defining the member on the class user?
Say I want to provide this class:
class i_want_a_static_member
{
static expensive_resource static_resource_;
public:
void foo()
{
static_resource_.bar();
}
};
Then the user of the class must not forget to define the static member somewhere
(as already answered many times):
// this must be done somewhere in a translation unit
expensive_resource i_want_a_static_member::static_resource_;
I do have an answer below, but it has some disadvantages. Are there better and/or more elegant solutions?
C++17 and above
Use inline static variables for non-dynamic initialization:
struct Foo
{
inline static int I = 0;
};
And use function local static variables otherwise:
struct Foo
{
static std::string& Bar()
{
static std::string S = compute();
return S;
}
};
C++14 and below
Use function local statics, as they are plain easier to use.
If for some reason you really wish for a static data member, then you can use the template trick:
template <typename T = void>
struct Foo
{
static int I = 0; // inline initialization only for simple types.
};
template <typename T>
int Foo<T>::I;
On local statics
For resources which require dynamic initialization, it is best to use a local static.
The order in which file-scope or class-scope statics are dynamically initialized is undefined, in general, leading to the Static Initialization Order Fiasco when you try to read a uninitialized static as part of the initialization of another. Local static solve the issue by being initialized lazily, on first use.
There is some slight overhead to using local statics, however. From C++11 onwards, the initialization is required to be thread-safe, which typically means that any access is gated by an atomic read and well-predicted branch.
My own solution is to use a templated holder class, as static members work fine in templates, and use this holder as a base class.
template <typename T>
struct static_holder
{
static T static_resource_;
};
template <typename T>
T static_holder<T>::static_resource_;
Now use the holder class:
class expensive_resource { /*...*/ };
class i_want_a_static_member : private static_holder<expensive_resource>
{
public:
void foo()
{
static_resource_.bar();
}
};
But as the name of the member is specified in the holder class, you can't use the same holder for more than one static member.
As of C++ 17. You can now use inline variables to do this:
static const inline float foo = 1.25f;
We have a singleton template class as defines below
template<class T> class Singleton{
T& reference(){
return objT;
}
private:
T objT;
};
And another user defined class which uses this singleton
class TestClass{
static Singleton<TestClass> instance;
static TestClass * getPointer()
{
return &instance.objT;
}
private:
TestClass(){}
};
template<TestClass>
Singleton<TestClass> TestClass::instance;
On compilation with GCC we are getting the error
In function static_initialization_and_destruction undefined reference to Singleton::Singleton().
What can be the reason for this.
Ignoring the fact, that in your example there is no need for Singleton template, consider this simplified example (I am using structs to avoid access issues):
template <class T>
struct Singleton
{
T object;
};
struct TestClass;
typedef Singleton<TestClass> TCS;
TCS test1; // not ok, no definition of TestClass available;
struct TestClass
{
TestClass(){}
static TCS test2; // not ok, no definition of TestClass available;
};
TCS test3; // ok, TestClass is defined;
To declare a member of type T, you need a complete definition of this type T. So, test1 and test2 are not legal - there is only a declaration, not definition of T. On the contrary, test3 is legal - it is located after the complete definition of the class. Easiest fix here is to use pointer to type - to declare a pointer to type T, you need a declaration instead of definition for the type T:
template <class T>
struct Singleton
{
T * object;
};
static Singleton<TestClass> instance;
you are actually trying to create an instance of class Singleton in above line; which will look for default constructor Singleton() (which is already present as you haven't explicitly defined it private).
T& reference() is a private method in your class.
And I didn't really understand this
template<TestClass>
Singleton<TestClass> TestClass::instance;
Are you sure what you are trying to do? Cause am not ;)
Maybe you want to read this to understand what you are doing http://www.yolinux.com/TUTORIALS/C++Singleton.html
Easiest fix: Don't use a singleton.