0
votes

I am trying to get shared pointers of a base class from a derived class. Here's the code:

class Base {
    public:
    typedef std::shared_ptr<Base> Ptr;
    Base();
    Base(const Base& orig);
    virtual Ptr getShared() = 0;
};


class Derived : public Base {
    public:
    // default constructor and copy constructor
    virtual Base::Ptr getShared() {
        return std::make_shared<Derived>(this);
    }
};

I am trying to use it to get a vector of Base::Ptr, like so:

std::vector<Base::Ptr> objects;
Derived d;
objects.push_back(d.getShared()); 

I'm running into problems with the copy constructor, and I know this has to do with breaking const-correctness by trying to cast a pointer to a ref behind the scenes. I just can't pinpoint what the cause is, or I'm making a wrong assumption. Any thoughts?

Base.h:20:5: note: no known conversion for argument 1 from 'Base*' to 'const Base&' Base.h:19:5: note: candidate: Base::Base()

Edit: Severin's answer led me to the right solution for this particular problem. Sahu's answer is correct, but I was trying to have multiple objects share a pointer for a single object. enable_shared_from_this is the way to go if you need multiple references to the same object without constructing additional instances. The catch is that calling make_shared on a pointer the first time does what you expect, but subsequent calls using the same pointer construct additional instances of that object using the pointer as an argument to the constructor. Correct usage of enable_shared_from_this will instead return a shared_ptr that shares access with all other shared_ptrs that reference the object.

Edit 2: For completeness, this situation was actually caused by misunderstanding the differences between passing by reference and passing by pointer. In this particular case, the real problem was a design decision elsewhere in the application. Food for though for others with similar problems.

2
looks like you want *this instead of thiskmdreko

2 Answers

1
votes

The signature of std::make_shared (until C++17) is

template< class T, class... Args >
shared_ptr<T> make_shared( Args&&... args );

It will construct an object of type T, wrap a shared_ptr around it and return the shared_ptr. See http://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared for the details.

Use of

    return std::make_shared<Derived>(this);

is invalid since you cannot construct an object of type Derived from a Derived*. You need to change that line to:

    return std::make_shared<Derived>(*this);

It returns a shared_ptr that wraps a newly copy-constructed Derived object.

0
votes

The problem is in this line:

virtual Base::Ptr getShared() {
    return std::make_shared<Derived>(this);
}

Base::Ptr is of type std::shared_ptr<Base>.
std::make_shared<Derived>(this) will return an std::shared_ptr<Derived>

Even if Derived inherit from Base, std::shared_ptr is a templated class, and shared_ptr<Derived> does not inherit from shared_ptr<Base>

What you want is to return the correct shared pointer:

virtual Base::Ptr getShared() {
    return std::shared_ptr<Base>(this);
}