0

I want to create two objects A and B, such that A.b() returns a reference to B if it is still alive, otherwise, null, and vice versa for B.a(). Has this problem been solved in a standard or widely-used utility library somewhere before?

I've run into two separate instances of this problem recently. I'm particularly interested in solutions in C++ but it might be useful to see how Rust or other non garbage-collected languages approach this.

I think this be done using reference-counting (store A and B using std::shared_ptr and keep std::weak_ptr references), and I can also think of an approach that avoids that (manage the lifetimes of A and B using whatever method you prefer, and store both plain references as well as booleans indicating liveness; update the boolean inside B when A is deleted and vice versa; in multi-threaded context, add a lock). But my workplace discourages use of std::shared_ptr, and the latter solution seems a little complex to me. I'm wonderingi f there's something simpler.

dysonsfrog
  • 155
  • 1
  • 6
  • 1
    Your second approach is exactly what `std::weak_ptr` does, isn't it? At least I don't see a difference there – UnholySheep Aug 25 '20 at 15:40
  • *"But my workplace discourages use of `std::shared_ptr`"* - for what reason? If they have a good argument and alternative then you should use that, but discouraging it for no reason seems like a bad idea – UnholySheep Aug 25 '20 at 15:41
  • I am curious to why your workplace discourages it as well? – Geno C Aug 25 '20 at 15:42
  • 1
    Semi-related: There is no built-in solution for this in Rust either (at least that I know of). The compiler would either stop you from compiling unless you can guarantee that the lifetime of a referenced object cannot outlive the reference or you would have to use something based around reference-counted objects as well – UnholySheep Aug 25 '20 at 15:48
  • > Your second approach is exactly what std::weak_ptr does, isn't it? It's slightly different in that `A` and `B` can be managed using `std::unique_ptr` or something else instead of reference-counting, but in hindsight I'm not sure it offers any real advantage. The accounting at deletion time has similar downsides to reference-counting itself. – dysonsfrog Aug 25 '20 at 15:53
  • I believe they discourage `std::shared_ptr` (not strictly banned, just have to convince people it can't be avoided w/ better design) with the reasoning that unique ownership is simpler to reason about. The performance hit for reference counting is probably relevant to but I think that's a lesser concern. – dysonsfrog Aug 25 '20 at 15:53
  • I mean, you can write your own system that manages this (e.g.: by assigning IDs to each object and then your `A` and `B` only store the id and request from your system to give the object or null). But IMO you would only do that if you can prove a tangible benefit over using the standard library – UnholySheep Aug 25 '20 at 16:05

1 Answers1

0

Has this problem been solved in a standard

Yes. Weak pointers can be used to achieve this.

Also destructors, as you have noted. That is less generally applicable than weak pointers. It should work when you have one-to-one relationship.

and store both plain references as well as booleans indicating liveness

Simpler solution: Use pointers. No need for a boolean, and the object can be made assignable.

But my workplace discourages use of std::shared_ptr, and the latter solution seems a little complex to me. I'm wonderingi f there's something simpler.

You want to have a complex relationship with lifetimes of two objects. I don't think there is a simpler solution. You need to choose:

  • Use shared and weak pointers against the discouragement. Document carefully the reasons for why it is needed.
  • Use the destructor approach. It's not terribly complex in my opinion.
  • Re-design so that you don't need this complex relationship.
eerorika
  • 232,697
  • 12
  • 197
  • 326