make_unique 无法编译以创建单例实例

make_unique doesn't compile for creating a singleton instance

全部,

我正在使用 C++14 并正在制作一个或多或少的标准单例。我正在使用最新的 Visual Studio 2017。此代码有效:

#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;

但是,当我将单例实例的创建更改为:

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

我在尝试访问私有成员时遇到编译错误:

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

这对我来说就像一个错误,因为这两种形式在功能上应该是相同的?想法?

std::unique_ptr<>的目的是控制指向的对象的生命周期。您可以传递一个 std::unique_ptr<> ,但这也会转移所指向对象的所有权。这个概念和单例的概念不太吻合。只有一个地方允许创建(或删除)单例。你真的不需要 std::unique_ptr<>。正如评论中已经说过的,有更简单的方法。我更喜欢@Praetorian 的建议:

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

你不能使用std::make_unique<>()实例化你的class的原因是构造函数是私有的。要访问它,您需要访问函数是 friend。看看 for that. Another solution is to provide a public constructor requiring a private type as argument, as described int .

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

这会在函数 make_unique 中创建 A。但是你要调用的 ctor 是私有的。

private:
  struct ctor_permission_t{
    explicit ctor_permission_t(int){};
  };
public:
  explicit A(ctor_permission_t):A(){}
};

然后

instance = std::make_unique<A>(ctor_permission_t{0});

ctor_permission_t 充当令牌,赋予其拥有者构建 A 的权利。我们将其传递给 make_unique.

ctor_permission_t 中的 explicit int 构造函数无法在不命名类型的情况下创建它,并且只有在 A 的实例和朋友中才能命名它,因为它是私有的。这使得绕过此权限令牌变得困难。

总结其他答案并修复其中的一些缺陷: 您可以使用私有构造函数创建一个私有结构,它是您 class 的朋友。然后使您的 class 构造函数 public 但带有该私有结构的附加参数。

另外最好使用静态函数 return 引用而不是裸静态变量。

#include <memory>

class A
{
  struct Private
  { 
    friend A;
    private:
      explicit Private() = default; 
  };

public:
  static A * getInstance()
  {
    if (!instance())
      instance() = std::make_unique<A>(Private());

    return instance();
  }

  A(Private) {};

private:
  static std::unique_ptr<A> & instance()
  {
    static std::unique_ptr<A> inst;
    return inst;
  }
};

或者如果您真的不需要任何需要使用指针和堆分配的特殊配置(例如在特殊线程中初始化实例或...):

class A
{
public:
  static A & getInstance()
  {
    static A instance;
    return instance;
  }

private:
  A() = default;
};