我有以下CPP源代码,用于使用unique_ptr创建类的Singleton对象:
#include <iostream>
#include <memory>
class A
{
public:
std::unique_ptr<A> getInstance(int log);
~A();
private:
static bool instanceFlag;
static std::unique_ptr<A> single;
A(int log);
int mLog;
};
bool A::instanceFlag = false;
std::unique_ptr<A> A::single = NULL;
std::unique_ptr<A> A::getInstance(int log)
{
if(!instanceFlag)
{
//single = std::make_unique<A>(log);
single = std::unique_ptr<A>(new A(log));
instanceFlag = true;
return std::move(single);
}
else
{
return std::move(single);
}
}
A::A(int log) :
mLog(log)
{
std::cout << "Called A cons" << std::flush << std::endl;
}
int main()
{
std::unique_ptr<A> mA = A::getInstance(5);
}
但是当我编译代码时,我得到以下错误:
$ c++ -std=c++11 try2.cpp
try2.cpp: In function 'int main()':
try2.cpp:45:41: error: cannot call member function 'std::unique_ptr<A> A::getInstance(int)' without object
std::unique_ptr<A> mA = A::getInstance(5);
^
但是我的项目中的代码格式完全一样,我收到错误:
Source code Line 39: single = std::make_unique<A>(log);
编译错误:
39: required from here
single = std::make_unique<A>(log);
error: A(int log)' is private
A::A(int log) :
^
答案 0 :(得分:4)
首先是静态问题。这样:
std::unique_ptr<A> getInstance(int log);
是一个实例方法。您需要A
的实例才能将其调用,但是您无法在不调用此方法的情况下获取A
的实例,因此......
使用实例方法的原因是他们可以访问他们调用的实例。您的方法仅使用以下成员:
static bool instanceFlag;
static std::unique_ptr<A> single;
由于它们是静止的,因此不需要实例。只需将方法设置为静态,并且无需先从某处获取A
即可调用它。
第二,逻辑问题。您的getInstance
方法会向您的单个实例返回unique_ptr
。 unique_ptr
的全部内容是唯一:只有一个指针拥有并控制对象的生命周期。当您返回unique_ptr
时,将单件对象的所有权从单身类本身转移给调用者。您甚至明确地调用move
来明确表明这种情况正在发生。
现在,在调用getInstance
一次之后,你的单身人士完全被打破了。如果再次调用getInstance
,单身人士认为它有一个实例(因为instanceFlag
),但unique_ptr
处于不确定状态。我们唯一可以肯定的是,它没有控制A
的实例。
只需将原始指针(或引用)返回A
,而不是转移所有权。
答案 1 :(得分:3)
简短回答:不要使用单身人士。
答案很长:std::make_unique()
使用它尝试创建的对象的构造函数,并且在您的代码中它是私有的。由于它是外部功能,因此不可能。您可以自己创建一个对象并将其传递给std::unique_ptr
进行管理,就像您在注释对象下面的行一样。
最重要的问题是,当您执行std::move()
时,您的班级成员single
已不复存在。或者,更准确地说,处于未指定的状态。随着对getInstance
的任何下一次通话,您都会通过......某事。您应该使用std::shared_ptr
,您希望通过复制或返回引用返回std::unique_ptr
。
答案 2 :(得分:0)
问题在于,正如错误日志所示,您在没有任何实例的情况下调用member function
即getInstance
。函数std::unique_ptr<A> getInstance(int log);
应声明为static
。
声明static
如下:
static std::unique_ptr<A> getInstance(int log);
注意:在单例模式中 getInstance
函数始终是静态函数。
以下是Wikipedia的摘录:
单例模式的实现必须:
- 确保只存在单例类的一个实例;和
- 提供对该实例的全局访问权。
通常,这可以通过以下方式完成:
- 声明该类的所有构造函数都是私有的;和
- 提供一个返回对实例的引用的静态方法。
实例通常存储为私有静态变量;在初始化变量时,在首次调用静态方法之前的某个时刻创建实例。
答案 3 :(得分:0)
即使在getInstance
静态之后,它也不会编译,因为缺少析构函数的定义。给出空定义或保留默认值。
~A() = default;
移动single
将首次运行并调用UB以便后续调用getInstance
。而是通过引用&
返回并删除std::move
static std::unique_ptr<A>& getInstance(int log);
std::unique_ptr<A>& A::getInstance(int log)
{
if(!instanceFlag)
{
//single = std::make_unique<A>(log);
single = std::unique_ptr<A>(new A(log));
instanceFlag = true;
return single;
}
else
{
return single;
}
}
在main()
内,您可以通过引用获得
std::unique_ptr<A>& mA = A::getInstance(5);