The C++ Standard specifies that a pr-value is (among others) “a function call or an overloaded operator expression, whose return type is non-reference”.
Now I wonder why that exactly is the case, because a pr-value is said to be an expression (or evaluation thereoff) that “can be moved from” and “doesn’t have identity”. I’d like to know what the part about the identity specifically means, because as is, I don’t think this is a very satisfactory statement. It is sometimes linked to the object existing in storage, but that part is similarly confusing as well, as I will lay out now:
Let’s say we have a function that passes parameters by value, and returns an object by value:
manipulateB(B objectB) {
//do something with B optionally manipulate it, and then return it by value
return objectB
}
When objectB is returned (either it is still the same object because of copy elision, or instead it copy constructed) in the main function
int main() {
B b = B();
B c = manipulateB(b)
}
then the functioncall “manipulteB(b)” has the value category pr-value, but there is an object of type B in the storage, and that object obviously has identity. It doesn’t yet have a name, but it is already there. It is then either assigned to object c, either via copy assignment, or, when there is copy elision, c is directly initialized with the object in the memory.
Now I wonder, why is it that the function call is a pr-value, despite there being an object in the scope?
There are some points where I think I might have misconcepted something, and I’d like to understand which one (or several) of them is the root für my misunderstanding:
- The value-category is a property of the expression “manipulateB(b)” in the code. While there might be an object of type B in the memory after the evaluation of that expression, there is no well defined way of attributing this place in memory to the expression “manipulateB(B objectB)”. Especially, another function call
B d = manipulateB(b)
might yield an other object in memory. The object in the memory will afterwards belong to the expressions “d” and “c”, but not to the expression “manipulateB(b)”. And calling the Address-of operator on “manipulateB(b)” is neither possible, nor meaningful.
-
At the moment the expression is evaluated, it is not clear if there is an object of type B in the storage at all. After the complete assignment statement has been carried out, there exists an object of type B in the storage that is assigned to the expression b, but this object doesn’t have any ties to the expression “manipulateB(b)”.
-
The property of a value-category is a rather abstract notion on the level of source code. When it is stated that an expression does have “identity”, then what is meant by that is that an object (that can have internal states) is associated with this expression. Depending on the methods and members of type B, the outcome of any expression involving the expression “b”, “c” or “d” may depend on the state of “b”. Contrary to that, modulo those dependencies, the outcome of “manipulateB(b)” doesn’t depend on anything.
I hope I was able to explain my confusion, and possible ways out of it. Which of the misconceptions that I have outlined is true and the reason why such a function call is not a pr-value?