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.
v.begin().operator=(v.begin().operator++()). It is sometimes useful, but it does lead to odd code compiling when those member functions are overloaded operators.fooshould take the iterator by value. That’s how iterators are intended to be used. It’s very unusual to traffic in references to iterators.