Search code examples
c++singletonc++14unique-ptrprivate-constructor

make_unique doesn't compile for creating a singleton instance


All,

I am using C++14 and am making a more-or-less standard Singleton. I am using the latest Visual Studio 2017. This code works:

#include <memory>
class A
{
public:
  static A& getInstance()
  {
    if (instance == nullptr)
      instance = std::unique_ptr<A>(new A());
    return *instance;
  }

private:
  A() {}
  static std::unique_ptr<A> instance;
};
std::unique_ptr<A> A::instance = nullptr;

However, when I change the creation of the singleton instance to this:

instance = std::make_unique<A>();

I get a compilation error that I am trying to access a private member:

Error   C2248   'A::A': cannot access private member declared in class 'A'      
c:\program files (x86)\microsoft visual studio\2017\professional\vc\tools\msvc\14.14.26428\include\memory   2510    

This feels like a bug to me, as the two forms should be identical in function? Thoughts?


Solution

  • The purpose of std::unique_ptr<> is to control the lifetime of the object pointed to. You may pass a std::unique_ptr<> around, but that will also transfer ownership of the object pointed to. This concept does not match very well with the concept of a singleton. There is only one place that is ever allowed to create (or delete) the singleton. You don't really need a std::unique_ptr<>for that. As already said in the comments, there are simpler ways for that. I would prefer @Praetorian's suggestion:

    static A& getInstance() 
    {
         static A instance;
         return instance;
    }
    

    The reason why you can't use std::make_unique<>() to instantiate your class is that the constructor is private. To access it, you need the accessing function to be a friend. Have a look at How to make std::make_unique a friend of my class for that. Another solution is to provide a public constructor requiring a private type as argument, as described int this solution.