Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

To support move semantics, should function parameters be taken by unique_ptr, by value, or by rvalue?

One of my function takes a vector as a parameter and stores it as a member variable. I am using const reference to a vector as described below.

class Test {
 public:
  void someFunction(const std::vector<string>& items) {
   m_items = items;
  }

 private:
  std::vector<string> m_items;
};

However, sometimes items contains a large number of strings, so I'd like to add a function (or replace the function with a new one) that supports move semantics.

I am thinking of several approaches, but I'm not sure which one to choose.

1) unique_ptr

void someFunction(std::unique_ptr<std::vector<string>> items) {
   // Also, make `m_itmes` std::unique_ptr<std::vector<string>>
   m_items = std::move(items);
}

2) pass by value and move

void someFunction(std::vector<string> items) {
   m_items = std::move(items);
}

3) rvalue

void someFunction(std::vector<string>&& items) {
   m_items = std::move(items);
}

Which approach should I avoid and why?

like image 932
MaxHeap Avatar asked Oct 03 '17 16:10

MaxHeap


1 Answers

Unless you have a reason for the vector to live on the heap, I would advise against using unique_ptr

The vector's internal storage lives on the heap anyway, so you'll be requiring 2 degrees of indirection if you use unique_ptr, one to dereference the pointer to the vector, and again to dereference the internal storage buffer.

As such, I would advise to use either 2 or 3.

If you go with option 3 (requiring an rvalue reference), you are foisting a requirement on the users of your class that they pass an rvalue (either directly from a temporary, or move from an lvalue), when calling someFunction.

The requirement of moving from an lvalue is onerous.

If your users want to keep a copy of the vector, they have to jump through hoops to do so.

std::vector<string> items = { "1", "2", "3" };
Test t;
std::vector<string> copy = items; // have to copy first
t.someFunction(std::move(items));

However, if you go with option 2, the user can decide if they want to keep a copy, or not - the choice is theirs

Keep a copy:

std::vector<string> items = { "1", "2", "3" };
Test t;
t.someFunction(items); // pass items directly - we keep a copy

Don't keep a copy:

std::vector<string> items = { "1", "2", "3" };
Test t;
t.someFunction(std::move(items)); // move items - we don't keep a copy
like image 170
Steve Lorimer Avatar answered Oct 20 '22 13:10

Steve Lorimer