目前能想到的最完善的方案和这个类似:
要求Foo
类必须包含一个不带参的构造函数,这样的话,构造完成之后,用到的地方不用再把参数塞进getInstance
里。
和这个答主说的一样,问题在于,一般我们想把Foo
做成单例时,如果Foo
包含带参数的构造函数,意味着我们想直接通过参数构造一个全局唯一的实例。但是根据上一段话,我们也希望它同时包含不带参的构造函数方便后续调用。
但这样一来,这个不带参的构造函数的意义并不在于"构造",实际上我们期望不通过它来构造,就显得很不自然。而且可能一上来误用不带参的 ctor 导致这个单例没构造成功。
我期望的用法是:
Foo
包含一个带参构造函数(比如Foo::Foo(int a)
),只能通过它来构造;Foo::getInstance(123)
,则成功构造,后续应当支持Foo::getInstance()
这种简便写法;Foo::getInstance()
,则报错,停止构造目前想到的在无参的Foo::Foo()
中,直接抛异常。这样能满足以上需求,但是却很不优雅,希望Foo
类不动,通过修改singleton
来实现。
想了一晚上了,没想出好办法。
似乎只能把 初始化 和 获得引用 做成两个函数了。
#include <stdexcept>
#include <utility>
#include <mutex>
#include <memory>
//thread-safe singleton in c++11
//use shared ptr, because make_unique is avaliable only after c++14
template <typename T>
class singleton
{
public:
template<typename... Args>
static void init_instance(Args&&... args)
{
try {
std::call_once(init_flag,
[](Args&&... args)
{
p_instance = std::make_shared<T>(std::forward<Args>(args)...);
},
args...);
} catch (...) {
}
}
static T& get_instance()
{
if (p_instance == nullptr)
throw std::logic_error("instance not initialized.");
return *p_instance;
}
private:
singleton(void) = delete;
virtual ~singleton(void) = delete;
singleton(const singleton&) = delete;
singleton& operator = (const singleton&) = delete;
private:
static std::shared_ptr<T> p_instance;
static std::once_flag init_flag;
};
template <typename T> std::shared_ptr<T> singleton<T>::p_instance;
template <typename T> std::once_flag singleton<T>::init_flag;
用智能指针是为了在程序结束时正确析构;最好用unique_ptr,但是在c++11里没有make_unique,这里用shared_ptr也没什么错
1
innoink OP 终于想出一个还过的去的方案
|
2
agagega 2018-11-01 13:41:09 +08:00
你不分开,还得用异常来处理,多麻烦
|