Assuming we have two classes:
class A
{
...
}
class B : public A
{
...
}
Would it be better to write
std::deque<shared_ptr<A> > container;
or
std::deque<reference_wrapper<A> > container;
to create a container which is able to contain references to both of these classes and why?
In my case, the class containing the container wouldn't care, if a reference somehow became invalid.
However are there any caveats to take into account, when choosing one approach over the other?
Best Answer
Here's my opinion on the matter:
consider whether both variants can actually be used in your case.
reference_wrapper
is, by design, not default-constructible. That means you will not be able, for example, to callcontainer.resize()
when using the reference wrapper. Ashared_ptr
, on the other hand, is default-constructed to an invalid/NULL state. So, for some use cases, you can't use areference_wrapper
. To give some examples:The above examples already hint at something else: Usability and readability. Depending on your use case, you have to decide whether you prefer pointer-style notation (
shared_ptr
) or more-or-less-reference-style notation (reference_wrapper
) and whether that makes the code more maintainable. Personally I value this aspect quite highly.As pointed out in a comment to your question, the object lifetime also plays a role. When the container's lifetime is intended to exceed the lifetime of any of the referenced objects, you have to use
shared_ptr
(or maybe find a different system design). With references you need to be certain about the respective scopes. I also suspect that in your specific case, you should actually care about references becoming invalid -- if that can happen, you'd be in trouble, and it would usually be difficult to debug.Storing
shared_ptr
elements of course implies that the values you want to refer to are already stored in shared pointers. You can not create a shared pointer referencing an element created by some other means. So, if you need to refer to existing, non-shared elements, you can not useshared_ptr
and would have to go withreference_wrapper
or plain old pointers.As far as performance goes, I would not expect much of a difference.
reference_wrapper
usually uses a pointer internally, and the overhead for ashared_ptr
is usually negligible.All in all, I would base my decision around (a) my concrete use case, and (b) usability/maintainability/readability of the code using the container.