std::shared_ptr 模板因 C2440 而失败

std::shared_ptr template fails with C2440

我想为几个 类 执行 shared_ptr。我正在使用 static 工厂函数来封装私有构造函数:

#include <memory>

class MyClass
{
    public:

    static std::shared_ptr<MyClass> create() {
        auto a = std::shared_ptr<MyClass>(new MyClass());
        return a;
    }

    private:
        MyClass();
        ~MyClass();
    }
}

此模板在 VS2017 中因 C2440、(函数式转换)而失败,但在 VS2015 中工作正常,我不知道为什么。 make_shared-version 在两者中都可以正常工作,但需要 public 构造函数。

知道我遗漏了哪个选项吗?

看起来 VS2017 抱怨从 std::shared_ptr 访问析构函数,因此您可能希望将 std::shared_ptr 声明为 MyClass 的友元。对于 std::make_shared,您可以使用此答案中的技巧 How do I call ::std::make_shared on a class with only protected or private constructors?

class MyClass
{
public:

    static std::shared_ptr<MyClass> create() {
        struct make_shared_enabler : MyClass {};
        return std::make_shared<make_shared_enabler>();
    }

    // compiles fine for gcc without friend though
    //friend class std::shared_ptr<MyClass>;
private:
   MyClass() {}
   ~MyClass() {}
};

live example

除了其他答案:如果您不想将 std::shared_ptr 声明为您的 class 的朋友并且您不想让您的析构函数 public,您可以使用自定义删除器创建 shared_ptr。为此,您需要 MyClass 中的一些方法来访问私有析构函数并调用 delete。例如:

class MyClass
{
public:
    static std::shared_ptr<MyClass> create() {
        auto a = std::shared_ptr<MyClass>(new MyClass(),
            [](MyClass* ptr) { destroy(ptr); });
        return a;
    }
    static void destroy(MyClass* ptr) { delete ptr; }
    private:
        MyClass(){}
        ~MyClass(){}
};

// later in the source code
    auto ptr = MyClass::create();

您还可以将 destroy 方法声明为非静态方法,然后在内部自杀(少数情况下它确实有意义)。