L G
L G

Reputation: 21

std::shared_ptr template fails with C2440

I want to enforce shared_ptr for a few classes. I'm using a static factory function to encapsulating private constructors:

#include <memory>

class MyClass
{
    public:

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

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

This template fails with C2440, (function-style cast) in VS2017, but works fine in VS2015 and I have no idea why. A make_shared-version works fine in both but requires public constructors.

Any idea which option I'm missing?

Upvotes: 1

Views: 697

Answers (2)

pptaszni
pptaszni

Reputation: 8228

In addition to other answers: if you don't want to declare std::shared_ptr as a friend of your class and you don't want to make your destructor public, you can create a shared_ptr with the custom deleter. For that you will need some method from your MyClass that can access the private destructor and call delete. For example:

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();

You can also declare destroy method as non-static and commit a suicide inside (one of a few situations when it actually makes sense).

Upvotes: 1

Slava
Slava

Reputation: 44258

Looks like VS2017 complains about accessing destructor from std::shared_ptr, so you may want to declare std::shared_ptr as friend of MyClass. For std::make_shared you can use a trick from this answer 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

Upvotes: 2

Related Questions