mercredi 25 novembre 2020

Are there any downside to using `std::reference_wrapper

I am having a quite common problem, I have a class that must store a non-owning pointer to a different class object.

I know that:

  • The lifetime of the reference object is guaranteed to outlive the instance.
  • The referenced object is passed in a constructor and does not change with the exception of moves or assignment.
  • It is never invalid.
  • It is used in many methods.
  • It can be shared by many instances.

Think of e.g. a logger class which is not global.

These points lead me to this solution using a reference variable which guarantees validity:

struct Foo{};

struct Bar{
    Bar(Foo& foo):m_foo(foo){}

Foo& m_foo;
};

The big downside is Bar is unnecessarily almost immutable - no assignment, no move.

The usual thing I did was to store Foo as a pointer instead. This solves most of the issues except that it is no longer very clear that the pointer is always valid. Furthermore it adds a new small one that it can be invalidated in any method, which should not happen. (Making it const has the same downside as &). That makes me add assert(m_foo) to every method for the peace of mind.

So, I was thinking about just storing std::reference_wrapper<Foo>, it is always valid and it keeps Bar mutable. Are there any downsides compared to a simple pointer? I know that any method can still point it to e.g. a local variable but let's say that does not happen because it is perhaps hard to obtain a new valid instance of Foo. At least it is harder than simple =nullptr;

I know this approach is used for containers like std::vector so I assume it is okay, but I would like to know if there is any catch I should look for.

Aucun commentaire:

Enregistrer un commentaire