I have a singleton class with a private constructor. In the static factory method I do the following:
shared_ptr MyClass::GetInstance()
{
You should use Meyers singleton instead. You should ensure that your compiler supports C++11 magic static before.
Please take VTT's comment seriously.
To your question:
My question is: why new can invoke a private constructor but make_shared not?
The new
is actually used within a lambda in a member-function; Well, A lambda defines a local-class, and C++ standards permits a local-class within a member-function to access everything the member-function can access. And its trivial to remember that member functions can access privates..
std::make_shared
has no access to the privates of MyClass
. It's outside the scope of MyClass
Example:
class X{
X(){};
public:
static X* create(){ // This member-function can access private functions and ctors/dtor
auto lm = [](){ // This lambda inherits the same access of enclosing member-function
return new X();
};
return lm();
}
};
int main(){
auto x = X::create(); //valid;
auto y = new X(); //invalid;
}
As mentioned, std::make_shared
or its component parts don't have access to private members.
the call_once
and once_flag
are un-necessary. They are implicit in c++11 static initialisation,
You normally would not want to expose the shared pointer.
class MyClass
{
MyClass() {}
public:
static MyClass& GetInstance()
{
static auto instance = MyClass();
return instance;
}
};
However, there is one case I can imagine where you would want to expose a shared pointer to the impl - this is in the case where the class can choose to 'break off' or 'reset' the impl to a new one. In this case I would consider code like this:
class MyClass2
{
MyClass2() {};
static auto& InternalGetInstance()
{
static std::shared_ptr<MyClass2> instance { new MyClass2 };
return instance;
}
public:
static std::shared_ptr<MyClass2> GetInstance()
{
return std::atomic_load(std::addressof(InternalGetInstance()));
}
static void reset() {
std::atomic_store(std::addressof(InternalGetInstance()),
std::shared_ptr<MyClass2>(new MyClass2));
}
};
However, in the end, it is my view that 'staticness' of a class should be an implementation detail, and unimportant to the user of the class:
#include <memory>
#include <utility>
class MyClass
{
// internal mechanics
struct Impl {
auto doSomething() {
// actual implementation here.
}
};
// getImpl now becomes the customisation point if you wish to change the
// bahviour of the class later
static Impl& getImpl() {
static auto impl = Impl();
return impl;
}
// use value semantics - it makes for more readable and loosely-coupled code
public:
MyClass() {}
// public methods defer to internal implementation
auto doSomething() {
return getImpl().doSomething();
}
};
int main() {
// note: just create objects
auto mc = MyClass();
mc.doSomething();
// now we can pass the singleton as an object. Other functions don't even
// need to know it's a singlton:
extern void somethingElse(MyClass mc);
somethingElse(mc);
}
void somethingElse(MyClass mc)
{
}