I can't seem to get around this specific problem for some time now. For example if I have the following code:
void foo(std::vector<int>::iterator &it) {
// ...
}
int main(){
std::vector<int> v{1,2,3};
foo(v.begin());
}
I would get compile error:
initial value of reference to non-const must be an lvalue.
And my guess would be that I get the error because a.begin()
returns a rvalue.
If so how is it possible that the following expression works:
v.begin()=v.begin()++;
if v.begin()
is a rvalue?
If the function argument is an rvalue, the compiler deduces the argument to be an rvalue reference. For example, assume you pass an rvalue reference to an object of type X to a template function that takes type T&& as its parameter. Template argument deduction deduces T to be X , so the parameter has type X&& .
Move semantics allows you to avoid unnecessary copies when working with temporary objects that are about to evaporate, and whose resources can safely be taken from that temporary object and used by another.
Move semantics is about transferring resources rather than copying them when nobody needs the source value anymore. In C++03, objects are often copied, only to be destroyed or assigned-over before any code uses the value again.
The reason is historical. In the initial days of the language, there was simply no way for user code to express that a type's copy-assignment operator should only work on l-values. This was only true for user-defined types of course; for in-built types assignment to an r-value has always been prohibited.
int{} = 42; // error
Consequently, for all types in the standard library, copy-assignment just "works" on r-values. I don't believe this ever does anything useful, so it's almost certainly a bug if you write this, but it does compile.
std::string{} = "hello"s; // ok, oops
The same is true for the iterator type returned from v.begin()
.
From C++11, the ability to express this was added in the language. So now one can write a more sensible type like this:
struct S
{
S& operator=(S const &) && = delete;
// ... etc
};
and now assignment to r-values is prohibited.
S{} = S{}; // error, as it should be
One could argue that all standard library types should be updated to do the sensible thing. This might require a fair amount of rewording, as well as break existing code, so this might not be changed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With