Search code examples
c++oopinheritancepolymorphismshared-ptr

Point raw pointer to a shared_ptr


I started programming in C++ after a 1-year break, and I am having difficulties here and there (not that I really knew it before the break).

My current problem is that I don't know how to use pointers properly.

I have the following std::vector:

std::vector<std::shared_ptr<IHittable>> world;

Where IHittable is the interface of Hittable objects.

Now, in this std::vector, multiple derivations of IHittable are pushed, like Sphere, Triangle, etc.

Each of these derived classes has a function intersects() like this:

Intersection Sphere::intersects(const Ray & ray)
{
    auto x = ...
    ...
    return {x, this};
}

Intersection looks like this:

class Intersection
{
    public:
        Intersection(double t, IHittable * object);
        [[nodiscard]] double t() const;
        [[nodiscard]] IHittable * object() const;
    private:
        double t_;
        IHittable * object_ = nullptr;
};

I really don't know how to write this code correctly.

I need to return a this pointer from the member function intersects() of an object which is itself allocated dynamically and is stored in a std::shared_ptr.

Is there a way to handle this?

Another example:

std::vector<std::shared_ptr<IHittable>> world;
world.push_back(std::make_shared<Sphere>());
auto s = Intersection(4.0, world[0]);

Should work.

PS: I could just create multiple std::vectors without std::shared_ptr:

std::vector<Sphere> spheres;
std::vector<Triangles> spheres;
...

But IMHO, it would be nice to iterate over every object at once.

PS2: I am now using shared_from_this() and most of my code works, thanks.


Solution

  • I think this sounds like a good fit for std::enable_shared_from_this as Remy pointed out in the comments.

    I whipped up a simplified example which hopefully makes it clear how it can be used to achieve what you're after.

    class Intersection;
    
    class IHittable : public std::enable_shared_from_this<IHittable> { 
    public:
        virtual Intersection intersects( ) = 0;
        virtual void print( ) const = 0;
        virtual ~IHittable( ) = default;
    };
    
    class Intersection {
    public:
        Intersection( std::shared_ptr<IHittable> object )
            : object_{ std::move( object ) }
        { }
    
        void print_shape( ) const {
            object_->print( );
        }
    private:
        std::shared_ptr<IHittable> object_;
    };
    
    class Square : public IHittable {
    public:
        Intersection intersects( ) override {
            return Intersection{ shared_from_this( ) };
        }
    
        void print( ) const override {
            std::cout << "Square\n";
        }
    };
    
    int main( ) {
        std::vector<std::shared_ptr<IHittable>> objects{ 
            std::make_shared<Square>( ) };
    
        const auto intersect{ objects.front( )->intersects( ) };
        intersect.print_shape( );
    }