make_unique不能为创建单例实例而编译

时间:2018-06-22 21:06:30

标签: c++ singleton c++14 unique-ptr private-constructor

全部

我正在使用C ++ 14,并且正在制作或多或少的标准Singleton。我正在使用最新的Visual Studio2017。此代码有效:

#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 studio\2017\professional\vc\tools\msvc\14.14.26428\include\memory   2510    

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

2 个答案:

答案 0 :(得分:3)

class MyClass { private _myInstance: string; private _myDomID: string; private _myFunc = this.print.bind(this); constructor(ID: string, domID: string) { this._myInstance = ID; this._myDomID = domID; document.getElementById(domID).addEventListener('click', this._myFunc); } public print() { console.log(this._myInstance); } public cleanUp() { document.getElementById(this._myDomID).removeEventListener('click', this._myFunc); } 的目的是控制所指向对象的生存期。您可以传递一个std::unique_ptr<>,但这也将转移所指向对象的所有权。这个概念与单例概念不太匹配。只有一个地方可以创建(或删除)单例。您实际上并不需要std::unique_ptr<>。正如评论中已经提到的那样,有更简单的方法。我希望使用@Praetorian的建议:

std::unique_ptr<>

之所以不能使用static A& getInstance() { static A instance; return instance; } 来实例化您的类,是因为构造函数是私有的。要访问它,您需要访问函数为std::make_unique<>()。看看How to make std::make_unique a friend of my class。另一个解决方案是提供一个需要私有类型作为参数的公共构造函数,如int this solution所述。

答案 1 :(得分:3)

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

这将在函数A中创建make_unique。但是您要呼叫的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

explicit int中的ctor_permission_t ctor使得无法在不命名类型的情况下创建它,并且仅在A的实例和朋友中可以命名,因为它是私有的。这使得绕过此权限令牌很困难。