Reputation: 1532
I'm working on a class with a std::vector<std::unique_ptr<T>>
member. I want to write a getter for it but the naïve way to do that is to return some sort of collection containing std::unique_ptr<T>
. The problem is that this hints to the caller that they can take ownership (by moving from the pointers) which I don't want. Also, even if I would return const std::unique_ptr<T>
's, that approach doesn't hide the fact that I'm using std::unique_ptr
for storage, which is an implementation detail that I don't want to expose unnecessarily.
How can I write my getter? What should the return type of my getter be? Can it be std::span<T*>
? Should my std::vector
even contain smart pointers in the first place?
My current attempt looks like this but this seems way too complicated for just a simple getter. Do I really need this complicated transform stuff for every getter in modern C++?
public:
[[nodiscard]] std::ranges::view auto get_foos() const
{
return foos_ | std::views::transform([](const auto& foo) { return foo.get(); });
}
private:
std::vector<std::unique_ptr<Foo>> foos_;
Upvotes: 1
Views: 61
Reputation: 545
First of all, I would recommend returning references (or std::reference_wrapper
since naked references don't play nice inside containers) to make it clear to the caller that they do not own the objects, plus to show they are not null.
You should not use std::span
, because it does not hold ownership over the underlying data, which in your case will be some transformation of the member vector. You can return std::vector<T*>
or std::vector<std::reference_wrapper<T>>
instead.
As to whether a std::vector<std::unique_ptr<T>>
instead of simple std::vector<T>
makes sense, it does if you want to use polymorphism or to avoid those returned pointers/references dangling after the container gets resized.
If the latter is your concern, consider using a std::deque
or std::list
instead, depending whether you want to be able to add/remove elements just from the either end, or arbitrary position.
Upvotes: 0