std :: make_shared和受保护的/私有的构造函数

时间:2018-10-27 16:39:09

标签: c++

[编辑:原来我们甚至不需要重新解释演员表,这使它更加简单]

这是here的结果,我发现了一种使用重新解释强制转换和共享指针别名构造函数的更好解决方案。它允许ctor和dtor都是私有的,并且可以使用最终的说明符。

信誉系统不允许我将其作为该问题的答案,所以我不得不将其作为另一个问题...

#include <iostream>
#include <memory>

class Factory final {
public:
    template<typename T, typename... A>
    static std::shared_ptr<T> make_shared(A&&... args) {
        auto ptr = std::make_shared<Type<T>>(std::forward<A>(args)...);
        return std::shared_ptr<T>(ptr, &ptr->type);
    }
private:
    template<typename T>
    struct Type final {
        template<typename... A>
        Type(A&&... args) : type(std::forward<A>(args)...) { std::cout << "Type(...) addr=" << this << "\n"; }
        ~Type() { std::cout << "~Type()\n"; }
        T type;
    };
};

class X final {
    friend struct Factory::Type<X>;  // factory access
private:
    X()      { std::cout << "X() addr=" << this << "\n"; }
    X(int i) { std::cout << "X(...) addr=" << this << " i=" << i << "\n"; }
    ~X()     { std::cout << "~X()\n"; }
};

int main() {
    auto ptr1 = Factory::make_shared<X>();
    auto ptr2 = Factory::make_shared<X>(42);
}

在gcc下提供以下输出...

X() addr=0x62bc30                                                                                                      
Type(...) addr=0x62bc30                                                                                                    
X(...) addr=0x62bc50 i=42                                                                                              
Type(...) addr=0x62bc50                                                                                                
~Type()                                                                                                                
~X()                                                                                                                   
~Type()                                                                                                                
~X()  

1 个答案:

答案 0 :(得分:0)

只是一个后续操作...上面的方法在std :: enable_shared_from_this <>中不能很好地起作用,因为初始的std :: shared_ptr <>是包装器的,而不是类型本身的。我们可以使用与工厂兼容的等效类来解决这个问题。

#include <iostream>
#include <memory>

template<typename T>
class EnableShared {
    friend class Factory;  // member access
public:
    std::shared_ptr<T> shared_from_this() { return weak.lock(); }
protected:
    EnableShared() = default;
    virtual ~EnableShared() = default;
    EnableShared<T>& operator=(const EnableShared<T>&) { return *this; }  // no slicing
private:
    std::weak_ptr<T> weak;
};

class Factory final {
public:
    template<typename T, typename... A>
    static std::shared_ptr<T> make_shared(A&&... args) {
        auto ptr = std::make_shared<Type<T>>(std::forward<A>(args)...);
        auto alt = std::shared_ptr<T>(ptr, &ptr->type);
        assign(std::is_base_of<EnableShared<T>, T>(), alt);
        return alt;
    }
private:
    template<typename T>
    struct Type final {
        template<typename... A>
        Type(A&&... args) : type(std::forward<A>(args)...) { std::cout << "Type(...) addr=" << this << "\n"; }
        ~Type() { std::cout << "~Type()\n"; }
        T type;
    };
    template<typename T>
    static void assign(std::true_type, const std::shared_ptr<T>& ptr) {
        ptr->weak = ptr;
    }
    template<typename T>
    static void assign(std::false_type, const std::shared_ptr<T>&) {}
};

class X final : public EnableShared<X> {
    friend struct Factory::Type<X>;  // factory access
private:
    X()      { std::cout << "X() addr=" << this << "\n"; }
    X(int i) { std::cout << "X(...) addr=" << this << " i=" << i << "\n"; }
    ~X()     { std::cout << "~X()\n"; }
};

int main() {
    auto ptr1 = Factory::make_shared<X>();
    auto ptr2 = ptr1->shared_from_this();
    std::cout << "ptr1=" << ptr1.get() << "\nptr2=" << ptr2.get() << "\n";
}