Reputation: 1975
The standard states in [basic.lval]/5 the following:
[..] The result object of a prvalue is the object initialized by the prvalue [..]
which is synchronized with the definition of a prvalue stated in [basic.lval]/(1.2):
A prvalue is an expression whose evaluation initializes an object [..]
So as far as I understand, the evaluation of a prvalue expression initializes an object called "result object", and this "result object" is the object that's initialized by this prvalue. For example:
struct S {};
int main(void){
S s = S();
}
here S()
is a prvalue expression, and I think that s
is its result object (may be incorrect, and that's what I am asking for) because, per the first quote, s
is the object initialized by the prvalue S()
. Now, if s
actually is the result object, where does the result object here:
struct X {};
int main(void){
X();
}
here X()
prvalue has no result object because it isn't initialized by any objects; Right?
I fell into this confusion when I saw the following code in Clang AST: (I'm sorry for trying to open an unrelated question, but I will summarize AFAIC)
struct Y {};
int main() {
Y y = Y();
}
The following is the AST produced from the above code: (...omitted...)
....
...
`-FunctionDecl <line:5:1, line:7:1> line:5:5 main 'int ()'
`-CompoundStmt <col:12, line:7:1>
`-DeclStmt <line:6:5, col:14>
`-VarDecl <col:5, col:13> col:7 y 'Y':'Y' cinit
`-CXXTemporaryObjectExpr <col:11, col:13> 'Y':'Y' 'void () noexcept' zeroing
The last line shows clearly there's an un-materialized temporary get created. When I tried to understand why this temporary object was created, correctly or incorrectly, I checked this text in the standard: ([class.temporary]/3)
When an object of class type X is passed to or returned from a function, if X has at least one eligible copy or move constructor ([special]), each such constructor is trivial, and the destructor of X is either trivial or deleted, implementations are permitted to create a temporary object to hold the function parameter or result object.
[..]
I'm not sure that I have spotted the correct paragraph. But if so, the above paragraph says that the created temporary object holds the "result object", and I see that the result object here is y
; right? I have confusion here: how the result object is y
meanwhile y
is not yet initialized? Does the result object here is the object produced from the constructor call? or something else?
I apologize if there are any conflicts in my questions or if the questions are based on misunderstanding.
Upvotes: 2
Views: 258
Reputation: 76628
and I think that s is its result object
Yes, correct. In particular there is no temporary object that could be the result object instead (since C++17).
here X() prvalue has no result object because it isn't initialized by any objects; Right?
The expression X()
in the expression statement X();
is a discarded-value expression per [stmt.expr]/1.
After potential conversions which are not relevant here, a prvalue expression that is a discarded-value expression has the temporary materialization conversion applied per [expr.context]/2.
The effect of temporary materialization conversion is to introduce a temporary object that is initialized from the prvalue per [conv.rval].
This temporary object is therefore the result object of the prvalue.
I fell into this confusion when I saw the following code in Clang AST
CXXTemporaryObjectExpr
probably (I am guessing here) only indicates an expression of the form T(E)
where T
is a non-reference type and E
is either an empty expression list or a list of two or more expressions and isn't intended to state anything about applied temporary materialization conversions.
Before C++17, this syntax generally caused the creation of a temporary object (before optional copy elision), which is why the name makes sense. Since C++17 there are many cases where this expression syntax will not cause the creation of a temporary object as you demonstrate. They probably simply didn't change the Clang-internal naming.
Your quote from the standard is not relevant here since there is no function that takes or returns a S
.
Note that the above applies to C++17 and later only.
Upvotes: 0