0

I dont exactly know, how to handle the problem, where one class uses shared pointers but I want to call its method from inside other class via this pointer.

class Bar {
public:
   Bar() = default;
   ~Bar() = default;

   void OnChange(std::shared_ptr<Foo> foo) { ... }
}


class Foo {
public:
   Foo(std::shared_ptr<Bar> bar) : bar(bar) {};
   ~Foo() = default;

   void Run() { 
      bar->OnChange(this); // <=== this wont work 
   }

private:
   std::shared_ptr<Bar> bar;
}

How can I create "clean" design so that Foo can cann OnChange form Bar?

  • Should I use std::enable_shared_from_this for Foo?
  • Should I add OnChange(Foo* foo) to Bar?
  • Some other solution?
3
  • 2
    shared_ptr is probably the wrong tool for your purpose. See: stackoverflow.com/questions/10826541/…
    – Doc Brown
    Dec 18, 2021 at 10:41
  • Why does OnChange need to share ownership? Is there a good reason it can't be passed a reference instead? Dec 18, 2021 at 11:51
  • 1
    ... yep, wh not design this as Bar::OnChange(const Foo &foo)?
    – Doc Brown
    Dec 18, 2021 at 11:54

1 Answer 1

5

The problem in your design is that shared_ptr is meant to manage memory allocation and destruction of objects if they are no longer used. There is no guarantee in your design that the foo object was allocated dynamically, i.e. that a shared_ptr could be made with this .

For this design to work you must let Foo inherit from enable_shared_from_this<Foo> and return shared_from_this(). The link has an example for using it. But it's a little bit tricky. So here a nice step-by-step explanation about how to use it and the pitfalls to avoid: article

Additional thoughts: The option of using an OnChange(Foo* foo) looks easier but it might weaken your overall design: you might have to repeat yourself as both OnChange() would have to stay aligned. And you'd risk dangling pointers since OnChange() could store a copy of its parameter in a non local place, defeating in some subtle cases the reference counting.

3
  • enable_shared_from_this<Foo> - first time I saw this, this really twists my brain. I think the C++ architecture astronautes have stroke again. Actually, in the case of the OP, I would really prefer to use OnChange(const Foo& foo) instead.
    – Doc Brown
    Dec 18, 2021 at 11:53
  • @DocBrown yes, C++ folks love the CRTP like Romanseco broccoli IRL ;-) The reference approach that you propose is a nice alternative to the pointer version. But OnChange() could still use a & to transform the const Foo& into a const Foo* and store that pointer somewhere and defeat reference counting. So it all depends on the purpose of OnChange() and its contract.
    – Christophe
    Dec 18, 2021 at 12:13
  • ... reading the linked article, I think the people who invented this piled another overly complex solution on an already complex, error-prone solution to solve a problem which they would not have without the latter (and yes, I know I am exaggerating). The forgot completely what Antoine de Saint Exupéry once wrote about design.
    – Doc Brown
    Dec 19, 2021 at 7:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.