Home > OS >  Passing a vector of unique ptrs
Passing a vector of unique ptrs

Time:11-01

I have code that looks like:

vector<unique_ptr<Foo>> foos = ... // Init vector.

// Do some stuff.

func(std::move(foos)); // func should now own foos, I'm done with them.
// Takes ownership of foos.
void func(vector<unique_ptr<Foo>>&& foos);

Now inside func I want to refactor out a bit of code into a separate function that needs to use foos. I am wondering how to do this. The options I considered are:

void util_func1(const vector<Foo*>& foos); // Does not take ownership of foos
void util_func2(const vector<unique_ptr<Foo>>& foos); // Does not take ownership of foos

The first option seems in line with the recommendation for (non-vectors of) unique_ptr, if a function takes ownership, pass unique_ptr by value, if a function doesn't take ownership pass by raw ptr/ref. If I understand correctly, the recommendation is to never pass unique_ptr by const-ref. Which is essentially what util_func2 is doing.

My problems is that now func has gotten pretty ugly:

void func(vector<unique_ptr<Foo>>&& foos) {
  vector<Foo*> raw_ptr_foos;
  raw_ptr_foos.reserve(foos.size());
  for (auto foo : foos) raw_ptr_foos.push_back(foo.get());
  util_func1(raw_ptr_foos);
}

So is util_func2 the correct way to do this or should I bite the bullet and write the ugly conversion to raw_ptr_foos or is there a 3rd way?

CodePudding user response:

If you have C 20, you express it as concepts, and have a constrained template as your helper.

template <typename P, typename T>
concept points_to = requires(P p) {
    { *p } -> std::common_reference_with<T &>
} && std::equality_comparable_with<std::nullptr_t>

template <std::ranges::borrowed_range R, typename T>
concept indirect_range_of = points_to<std::ranges::range_value_t<R>, T>;

template <indirect_range_of<Foo> Foos>    
void util_func1(Foos foos);

void func(std::vector<std::unique_ptr<Foo>> foos) {
  util_func1(std::ranges::views::all(foos));
}

Prior to that you write a template, and optionally add sfinae or static_asserts

template <typename Foos
void util_func1(const Foos & foos);

void func(std::vector<std::unique_ptr<Foo>> foos) {
  util_func1(foos);
}

CodePudding user response:

If you want to access and change these vector elements in multiple functions, I would consider using shared_ptrs instead of unique_ptrs. This way you still don't have to worry about memory leaks at the end of function execution and you don't have to mess around with raw pointers.

  • Related