
目前能想到的最完善的方案和这个类似:
要求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 你不分开,还得用异常来处理,多麻烦 |