私有构造函数和make_shared

时间:2017-07-16 09:38:32

标签: c++ shared-ptr

我有一个带有私有构造函数的单例类。在静态工厂方法中,我执行以下操作:

shared_ptr<MyClass> MyClass::GetInstance()
{
    static once_flag onceFlag;

    call_once(onceFlag, []() {
        if (_instance == nullptr)
            _instance.reset(new MyClass());
    });

    return _instance;
}

如果我使用

_instance = make_shared<MyClass>();

代码无法编译。我的问题是:为什么new可以调用私有构造函数但make_shared不能调用?

3 个答案:

答案 0 :(得分:3)

  1. 如上所述,std::make_shared或其组成部分无权访问私人会员。

  2. call_onceonce_flag是不必要的。它们隐含在c ++ 11静态初始化中,

  3. 您通常不希望公开共享指针。

  4. class MyClass
    {
        MyClass() {}
    
    public:
        static MyClass& GetInstance()
        {
            static auto instance = MyClass();
            return instance;
        }
    };
    

    然而,有一种情况我可以想象你想要公开一个指向impl的共享指针 - 这是在类可以选择'中断'或'重置'impl到一个新的情况的情况下。在这种情况下,我会考虑这样的代码:

    class MyClass2
    {
        MyClass2() {};
    
        static auto& InternalGetInstance()
        {
            static std::shared_ptr<MyClass2> instance { new MyClass2 };
            return instance;
        }
    
    public:
    
        static std::shared_ptr<MyClass2> GetInstance()
        {
            return std::atomic_load(std::addressof(InternalGetInstance()));
        }
    
        static void reset() {
            std::atomic_store(std::addressof(InternalGetInstance()),
                            std::shared_ptr<MyClass2>(new MyClass2));
    
        }  
    };
    

    但是,最后,我认为类的“静态”应该是一个实现细节,对类的用户来说并不重要:

    #include <memory>
    #include <utility>
    
    class MyClass
    {
        // internal mechanics
    
        struct Impl {
    
            auto doSomething() {
                // actual implementation here.
            }
        };
    
        // getImpl now becomes the customisation point if you wish to change the
        // bahviour of the class later
        static Impl& getImpl() {
            static auto impl = Impl();
            return impl;
        }
    
    
        // use value semantics - it makes for more readable and loosely-coupled code
    public:
        MyClass() {}
    
        // public methods defer to internal implementation
    
        auto doSomething() {
            return getImpl().doSomething();
        }
    };
    
    
    int main() {
    
        // note: just create objects
        auto mc = MyClass();
        mc.doSomething();
    
        // now we can pass the singleton as an object. Other functions don't even
        // need to know it's a singlton:
    
        extern void somethingElse(MyClass mc);
        somethingElse(mc);
    }
    
    void somethingElse(MyClass mc)
    {
    
    }
    

答案 1 :(得分:1)

请认真对待VTT's comment

问题:

  

我的问题是:为什么new可以调用私有构造函数但make_shared不是?

new实际上是在成员函数中的lambda中使用的;好吧,lambda在成员函数中定义本地类和C ++标准permits 本地类来访问成员函数可以访问的所有内容。记住成员函数可以访问私有部分是微不足道的。

std::make_shared无权访问MyClass私有。它超出了MyClass

的范围

示例:

class X{
    X(){};
public:
    static X* create(){ // This member-function can access private functions and ctors/dtor
        auto lm = [](){ // This lambda inherits the same access of enclosing member-function
               return new X();
        };
        return lm();
    }
};

int main(){
    auto x = X::create();    //valid;
    auto y = new X();        //invalid;
}

答案 2 :(得分:0)

您应该使用Meyers singleton代替。您应该确保您的编译器之前支持C ++ 11 magic static。