0

I've read this link: What is the correct way of using C++11's range-based for?, I've known why we use auto && to loop a vector<bool>. But I still have one more question about auto & and auto &&.

class Test {};
vector<Test> vec = {Test{}, Test{}, Test{}};
vector<Test> vec2;
// case 1
for (auto &element : vec) {
    vec2.emplace_back(element);
}
// case 2
for (auto &element : vec) {
    vec2.emplace_back(std::move(element));
}
// case 3
for (auto &&element : vec) {
    vec2.emplace_back(element);
}
// case 4
for (auto &&element : vec) {
    vec2.emplace_back(std::move(element));
}

As you see, I'm trying to insert the objects from the vec into the vec2 with the method move constructor of the class Test.

I don't know which case I should use, which case is better, which cases are wrong.

Ofc, you might say that we can simply do vec2 = std::move(vec);, this is correct but I want to know how to move-construct each element in a for loop, instead of move-construct the container.

Yves
  • 11,597
  • 17
  • 83
  • 180
  • If you want to move, you can start by throwing away case 1 and 3. The other two are equivalent. – super Apr 27 '21 at 01:56
  • I vote Case 5, which is Case 4 except it uses `std::forward` and am making it a comment instead of an answer because I don't want to do the research right now. The type of `it` may be r-value reference, but `it` is itself an l-value, so it must be moved. What I'm unsure of is if `it` is a universal reference or not. I know `auto` type deduction is largely the same as regular template deduction, but I can't remember if this is an edge case or not. And that's all after I consider if forwarding is what I want or not. I'm starting to think not, and my vote moves back to Case 4 if that's the case. – sweenish Apr 27 '21 at 01:56
  • 3
    Case 1 and Case 3 are the same, Case 2 and Case 4 are the same here. – songyuanyao Apr 27 '21 at 02:04
  • @Jarod42 You are right, let me rename it. – Yves Apr 27 '21 at 07:53

1 Answers1

1

Unless there's a specific reason to write your own loop, I'd say none of the above. Instead, I'd use:

std::move(vec.begin(), vec.end(), std::back_inserter(vec2));

At least by my reading, this makes it fairly apparent both:

  1. what you're trying to accomplish, and
  2. that you're really doing what you want to.
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • I have questions about this code. The first is how this call to `std:::move` is supposed to work, and how it could possibly push anything back on `vec2` given that `std::vector::back()` is just for accessing the last element. Is there some voodoo I'm missing out on? – sweenish Apr 27 '21 at 02:00
  • @sweenish: Oops--typed the wrong thing there. – Jerry Coffin Apr 27 '21 at 02:01
  • I still don't follow. If this were `std::copy()`, it'd be closer, you'd just need a `std::back_inserter(vec2)` and not `vec2.end()`. But `std::move()` looks nothing like `std::copy()` – sweenish Apr 27 '21 at 02:03
  • 1
    @sweenish: There are two entirely different things called `std::copy`. The one you see a lot is basically just a cast to rvalue reference in disguise. But the other is a whole like like `std::copy`. https://en.cppreference.com/w/cpp/algorithm/move – Jerry Coffin Apr 27 '21 at 02:05
  • Okay, cool. I did not know this version of `std::move()` existed. But the example on that page does show that you'd still want `std::back_inserter(vec2)` and not `vec2.end()`. – sweenish Apr 27 '21 at 02:06
  • @sweenish: Yeah--I should probably know to stop and think for at least a second before typing things in, but apparently I never quite learn. At least my thesis was fairly quickly proven correct: the problem was almost immediately obvious to somebody looking at it who was actually thinking clearly. :-) – Jerry Coffin Apr 27 '21 at 02:08