mada
mada

Reputation: 1975

What actually a "result object" of a prvalue expression is?

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

Answers (1)

user17732522
user17732522

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

Related Questions