想了一晚上想不出一个完美的 c++ singleton 方案 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
innoink
V2EX    问与答

想了一晚上想不出一个完美的 c++ singleton 方案

  •  
  •   innoink 2018-11-01 01:28:31 +08:00 2467 次点击
    这是一个创建于 2550 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前能想到的最完善的方案和这个类似:

    https://stackoverflow.com/questions/24964769/singletons-curiously-recurring-template-pattern-and-forwarding-constructor-para/24966418#24966418

    要求Foo类必须包含一个不带参的构造函数,这样的话,构造完成之后,用到的地方不用再把参数塞进getInstance里。

    和这个答主说的一样,问题在于,一般我们想把Foo做成单例时,如果Foo包含带参数的构造函数,意味着我们想直接通过参数构造一个全局唯一的实例。但是根据上一段话,我们也希望它同时包含不带参的构造函数方便后续调用。

    但这样一来,这个不带参的构造函数的意义并不在于"构造",实际上我们期望不通过它来构造,就显得很不自然。而且可能一上来误用不带参的 ctor 导致这个单例没构造成功。

    我期望的用法是:

    1. Foo包含一个带参构造函数(比如Foo::Foo(int a)),只能通过它来构造;
    2. 如果程序第一次执行的是Foo::getInstance(123),则成功构造,后续应当支持Foo::getInstance()这种简便写法;
    3. 如果程序第一次执行的是Foo::getInstance(),则报错,停止构造

    目前想到的在无参的Foo::Foo()中,直接抛异常。这样能满足以上需求,但是却很不优雅,希望Foo类不动,通过修改singleton来实现。

    想了一晚上了,没想出好办法。

    第 1 条附言    2018-11-01 13:06:59 +08:00

    似乎只能把 初始化 和 获得引用 做成两个函数了。

    #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也没什么错

    3 条回复    2018-11-02 11:12:38 +08:00
    innoink
        1
    innoink  
    OP
       2018-11-01 13:09:33 +08:00
    终于想出一个还过的去的方案
    agagega
        2
    agagega  
       2018-11-01 13:41:09 +08:00
    你不分开,还得用异常来处理,多麻烦
    innoink
        3
    innoink  
    OP
       2018-11-02 11:12:38 +08:00 via Android
    @agagega 额,异常本来也是避免不了的,因为构造函数本身就有可能抛异常
    关于 &nsp;   帮助文档     自助推广系统     博客     API     FAQ     Solana     2679 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 07:12 PVG 15:12 LAX 00:12 JFK 03:12
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86