All,
我正在使用 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 studio2017professionalvctoolsmsvc14.14.26428includememory 2510
这对我来说感觉像是一个错误,因为这两种形式在功能上应该是相同的?思潮?
std::unique_ptr<>
的目的是控制指向对象的生存期。您可以传递std::unique_ptr<>
,但这也会转移指向对象的所有权。这个概念与单例的概念不太匹配。只有一个地方允许创建(或删除(单一实例。你真的不需要为此std::unique_ptr<>
。正如评论中已经说过的,有更简单的方法。我更喜欢@Praetorian的建议:
static A& getInstance()
{
static A instance;
return instance;
}
不能使用std::make_unique<>()
实例化类的原因是构造函数是私有的。要访问它,您需要访问功能是friend
.看看如何使std::make_unique我班的朋友。另一种解决方案是提供一个需要私有类型作为参数的公共构造函数,如本解决方案中所述。
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
ctor 使得在不命名类型的情况下无法创建它,并且只有在实例和A
的朋友中才能命名它,因为它是私有的。 这使得绕过此权限令牌变得困难。
总结其他答案并修复其中的一些缺陷: 您可以使用私有构造函数创建一个私有结构,该构造函数与您的类是朋友。然后使您的类构造函数公开,但使用该私有结构的附加参数。
此外,最好使用静态函数 witch 返回引用而不是裸静态变量。
#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;
};