C++ STL container - pop with move
Asked Answered
M

1

10

Is there a STL container (no Boost) from which an element can removed and moved to an lvalue?

Say I have a std::vector of large objects and a variable to which I want to pop an element from the vector.

var = vec.back();  // non-move assign op
vec.pop_back();    // dtor

var = containerWithMovePop.pop_and_return();  // move assign-op

It's not like performance is so important, I just want to know if it's possible.

Moonset answered 14/4, 2017 at 17:13 Comment(10)
Why not var = std::move(vec.back()); vec.pop_back();?Palmary
Ok, but what state would vec.back() be in between the two operations? Not valid I'd say, is that correct?Moonset
It will be in "moved-from" state. Whether is this state valid, depends on how type is implemented, but all std types are in "valid but unspecified" state, which is generally recomended for user defined types as well.Echovirus
@boofaz: The move is required to leave the object in a state that's valid to at least some degree, so you can still (at least) destroy it, which is all you're doing here. I believe you should be fine as long as you don't try to interleave any other use of the vector's data between the move and the pop_back.Hiatt
And any type is supposed to be at least destructible when moved-from, and you don't need anything more from it.Echovirus
Thanks, that makes sense.Moonset
I feel like pop_back() could return a value_type&&. Those who don't want the ex-element can ignore it, but those who do get to write 1 line, instead of 2 or 3.Undermanned
@Undermanned The reason pop() in general does not return is it can not be implemented efficiently. Implementing top() and pop() allows for an efficient implementation. More detail: cpptruths.blogspot.com/2005/10/…Bengali
@MartinYork That was written in 2005, before move semantics, which I wager change the answer quite a bit... although sure, for certain types, it would still cost a bit more to move and then destroy an ignored value, than it would to simply immediately destroy it as void-returning pop() does. Opting into that via a function with a different name that returns the value would be one solution. But I guess it's too trivial for the Standard to add that, and trivial enough that we can do it ourselves.Undermanned
@Undermanned I think you will find the same gotchas are relevant (especially when the type T does not support move) which is why this functionality was not added to the standard. The standard wants to make sure we can write generic code that is as efficient as possible (without overcomplicating things) in the most logical way possible.Bengali
T
2

As @aeschpler says, this works

auto var = std::move(vec.back()); 
vec.pop_back();

vec.back() will be empty (if string) or same (if int), or whatever (depends on the type) between back and pop_back, but that's fine. As the destructor runs in pop_back() there will be very little to do there.

We might get pop_back() to return T in the future now that we have move semantics (as ppl noted, we didn't when std::vector<> was specced), but likely it'd be a new method so to not destroy backward compatibility.

Tennison answered 25/8, 2021 at 18:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.