Luis
Luis

Reputation: 502

Use share_from_this instead of this pointer

I want to generate a shared_ptr from a class and use it instead of the this* raw pointer to initialize another one. The other expects a shared_ptr in Constructor. I'm showing only a excerpt:

class Soundfile : std::enable_shared_from_this<Soundfile> { ...more code

std::shared_ptr<Soundfile> Soundfile::getptr() {
     return  shared_from_this();
}

I need to initialize another class called Channel inside from Soundfile:

bool Soundfile::openRead(const char *filename_) { 
//more code ...
     channels = std::make_shared<Channel>(getptr() , windowSize_, gdata);
}

This doesn't works, I become a weak_ptr exception, I tried to do the following:

std::shared_ptr<Soundfile> Soundfile::getptr() {
    try {
        return shared_from_this();
    }
    catch (const std::bad_weak_ptr&) {
        return std::make_shared<Soundfile>();
    }
}

This works, but I become a new empty shared_ptr, I saved previously data inside the class Soundfile, I need to use it inside Channel, for this reason that is not what I'm looking for. I searched for a solution here, but I couldn't find one, sorry if the question is duplicated

EDIT: Here is a minimal example what I'm trying to explain:

class A : std::enable_shared_from_this<A> {
public:
    A() {}
    ~A() {}
    std::shared_ptr<A> getptr() {
        return shared_from_this();
    }
    void my_method() {
        myB = std::make_shared<B>(getptr());
    }
private:
    std::shared_ptr<B> myB;
};

class B {
public:
    B(std::shared_ptr<A> _myA)  {
        myA = _myA;
    }
    ~B() {}
private:
    std::shared_ptr<A> myA;
};

int main() {
    std::shared_ptr<A> myA = std::make_shared<A>();
    myA->my_method();

}

Upvotes: 0

Views: 161

Answers (1)

Markus Mayr
Markus Mayr

Reputation: 4118

std::enable_shared_from_this::shared_from_this only works if the instance is currently managed by a shared pointer.

You can think of enable_shared_from_this as a class that contains a weak_ptr. When passing an instance of a class that is derived from std::enable_shared_from_this to the shared_ptr constructor, that constructor will initialize the weak_ptr inside it. Calling shared_from_this will only work after the weak pointer has been initialized, because it is implemented by converting that weak_ptr to a shared_ptr.

If you call shared_from_this before the weak_ptr has been initialized, it will raise a bad_weak_ptr exception, because the cast to a shared_ptr fails.

In order to solve your problem, you have to make sure that any instance of Soundfile is managed by a shared_ptr before the getptr() method or any method calling it is called.

In those rare cases were I use shared_from_this, I usually make the constructors private and add static factory methods in order to enforce this:

class A {
    public:
        static std::shared_ptr<A> create() {
            return std::make_shared<A>();
        }
    private:
        A();
};

You still have to be careful what you are doing in your constructors, because shared_from_this won't work inside them.

Upvotes: 4

Related Questions