Home > OS >  Passing `this` to a function as a shared_ptr
Passing `this` to a function as a shared_ptr

Time:09-23

I am writing some example code that hopefully captures my current struggle. Let's assume I have a class for some general shapes Shape and a nice Function that doubles the perimeter of any shape

float DoublePerimeter (shared_ptr<Shape> shape)
  return 2*shape->GetPerimeter();
};

Is it possible to use such a function in a class itself?

class Square : Shape {
  float side = 1;
  public:
  void Square(float aside) : side(aside) {;}
  float GetPerimeter(){return 4*side;}
  void Computation() { DoublePerimeter (??????);}
};

What can I pass in the ?????? to make this work? I tried using something like

shared_ptr<Shape> share_this(this);

and also tried enable_shared_from_this<> for my class, however the pointer that I pass to the function always returns null on lock. Is this even possible, or is this bad design? Am I forced to make this function a member function?

CodePudding user response:

I've tried it out. It seems to work for me. See here or below. I fixed some small issues and made Computation return a value for demonstration purpose.

#include <memory>
#include <cassert>
#include <iostream>

class Shape {
    public:
    virtual float GetPerimeter(){return 0;}

};

float DoublePerimeter (std::shared_ptr<Shape> shape){
  return 2*shape->GetPerimeter();
}

class Square : public Shape, public std::enable_shared_from_this<Square> {
  float side = 1;
  public:
  Square(float aside) : side(aside) {}
  float GetPerimeter(){return 4*side;}
  float Computation() { 
      return DoublePerimeter (this->shared_from_this());
    }
};


int main(){
    auto square = std::make_shared<Square>(3.0);
    std::cout <<square->Computation() << std::endl;
    return 0;
}

edit:

Example for @pptaszni's comment. Changing the main to:

int main(){
    Square square{3.0};
    std::cout << (&square)->Computation() << std::endl;
    return 0;
}

will result in a runtime error:

Program returned: 139
terminate called after throwing an instance of 'std::bad_weak_ptr'
  what():  bad_weak_ptr

CodePudding user response:

If you don't want to use enable_shared_from_this, perhaps because your objects are not always owned by a shared pointer, you can always work around it by using a no-op deleter:

void nodelete(void*) {}

void Square::Computation() { DoublePerimeter({this, nodelete}); }

but it's a hack (and a fairly expensive one at that, since you're allocating and deallocating a control block just to con the function you're calling).

A cleaner solution, albeit one that might require more typing, is to separate your free function implementation from the ownership scheme:

float DoublePerimeter(Shape const& shape)
  return 2*shape.GetPerimeter();
};

float DoublePerimeter(std::shared_ptr<Shape> shape)
  return DoublePerimeter(*shape);
};

void Square::Computation() const { DoublePerimeter(*this); }
  • Related