Are function parameter objects temporary objects?
Asked Answered
O

4

10

The current C++ standard draft in [class.temporary]/7 contains the phrase

a temporary object other than a function parameter object

I was under the impression that function parameter objects are not temporary objects. However, this phrase was added relatively recently. So am I mistaken or misunderstanding the context?

Onanism answered 17/12, 2023 at 22:16 Comment(5)
Interesting question. My guess would be that it is identical to 6.9 but not so succinctly worded.Sorenson
@MaartenBodewes The purpose of the [class.temporary]/7 is to extend the lifetime in exactly that case to avoid an annoying range-for pitfall, so I don't think that is intended to be the meaning. See open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2644r1.pdf. Unfortunately there is no explanation for the "other than a function parameter object" part in there and I suspect it to be meaningless, but am not sure.Onanism
I think it means in for(auto x: {A{std::string{"abc"}}, A{std::string{"def"}}}), the lifetime of the two A objects are extended to the end of the for loop, however the lifetimes for std::string{"abc"} and std::string{"def"} themselves are not extended. (This is a special case where the "function" is the constructor call, but it applies to other functions as well, for example, for(auto x:{makeA(std::string{"abc"}), makeA(std::string{"def"})}))Dupe
@WeijunZhou Without seeing A's constructor it is impossible to tell whether the string objects are function parameter objects. If they are, because the constructor takes std::string by-value, then yes, I think those are not supposed to be extended, but I think that "other than a function parameter object" wouldn't affect that because these objects aren't temporary objects to begin with.Onanism
You mean they are just prvalues that haven't materialized under the new lifetime rule updated after C++17, and therefore are not temporary objects? OK I think that makes sense.Dupe
U
5

An example in [stmt.ranged] illustrates CWG's intent:

using T = std::list<int>;
const T& f1(const T& t) { return t; }
const T& f2(T t)        { return t; }
T g();

void foo() {
  for (auto e : f1(g())) {}     // OK, lifetime of return value of g() extended
  for (auto e : f2(g())) {}     // undefined behavior
}

So the "other than a function parameter object" wording is referring to the parameter t of f2.

I think the OP is right that this isn't actually a temporary object; it doesn't fall under any of the categories mentioned in [class.temporary]/1. However, on some implementations a function parameter object has temporary-like characteristics in that it might be destroyed at the end of the full-expression containing the call, rather than at the point you would expect for a block variable. And I think that was the case that CWG was trying to address here.

Upthrust answered 18/12, 2023 at 0:33 Comment(3)
I don't think that this is right. p3 says that only if the type is ABI-trivial, can a temporary object be created which is used to initialize the function parameter object. If the wording also applied to t in your f2, the paragraph would be totally unnecessary, since "other than a function parameter object" would apply to non-reference parameters in general.Kesler
Tbf there is a chance they you're still right and in the case of ABI-trivial parameters, both the function parameter object and the extra object used to initialize it are temporary. However, I don't think that's likely. The wording is very confusing in general and needs some editorial work.Kesler
@JanSchultke I know the wording is probably incorrect, but the CWG minutes do reflect that this example was added for the purpose of illustrating the specific exclusion that CWG wanted to make clear.Upthrust
P
2

Scrolling up to [class.temporary]/3:

implementations are permitted to create a temporary object to hold the function parameter

Not all parameter objects are temporary objects, but some are allowed to be.

Psychodynamics answered 17/12, 2023 at 22:33 Comment(3)
That temporary object is a distinct object from the function parameter object (which is the point of this exception to the mandatory copy elision rule). See the following "the function's parameter or return object is initialized as if by using the eligible trivial constructor to copy the temporary" after your quote.Onanism
@Onanism Maybe the wording of the draft needs to be updated then? As I read it, the intent is to exclude the temporaries created to hold a function parameter from having their lifetimes modified in /7. In for ( auto x : f(g()) ), a temporary object created from what f returns would be subject to paragraph 7, but a temporary object (if any) created from what g returns would not, similar to binding to a reference.Psychodynamics
The intent of the rule is to also extend the lifetime of any temporary object created from g() if e.g. f takes its argument by-reference. The question is what the intent is if f takes by-value, in which case, in my understanding, there is no temporary object to begin with, only the (non-temporary) function parameter object. That seems to be the excluded case which isn't included to begin with.Onanism
K
1

The arguments passed to function parameters aren't always temporary. They are only temporary in a special case:

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. The temporary object is constructed from the function argument or return value, respectively, and the function's parameter or return object is initialized as if by using the eligible trivial constructor to copy the temporary (even if that constructor is inaccessible or would not be selected by overload resolution to perform a copy or move of the object).

[Note 4: This latitude is granted to allow objects of class type to be passed to or returned from functions in registers. — end note]

- [class.temporary] p3

Note that the condition is quite complicated here, and this is deliberate. Instead of saying that all trivially copyable types are passed as a temporary object, the condition ignores the copy/move assignment operators and mirrors the requirement of "ABI-triviality" in the System-V ABI, i.e. the requirements for pass-by-register.

Outside of this special case, function parameter objects are not temporary objects. One important distinction is that temporary objects are always destroyed at the end of the surrounding full-expression ([class.temporary] p4), but function parameter objects can be destroyed by the callee ([expr.call] p6).

Note that this paragraph states that the function parameter object isn't the temporary object but a trivial copy of it, and p7 suggests that the function parameter object itself could be temporary. I believe this to be an editorial mistake in p7.

Kesler answered 17/12, 2023 at 22:34 Comment(3)
But that temporary object is a distinct object from the function parameter object. The latter is initialized from the former as your quote states.Onanism
@Onanism personally, I think the wording is just a bit clunky. The object used as a function parameter is never a temporary object, but what is passed can be an additional temporary object according to this wording. I would assume that p7 refers to this additional temporary object and [class.temporary] needs some editorial work to tie it all together.Kesler
That could be the intent, but then the current wording simply seems wrong. I think it is equally possible that it isn't intended to mean anything that it wouldn't without the qualification, but that the author intended to emphasize that the lifetime rules of function parameter objects aren't affected.Onanism
A
0

Parameter objects that are passed by value are temporary objects in the sense that they are created on function call, and destroyed on function return. They are described so in Stroustrup language definition, so I think this has not changed over time. Of course, object parameter that are pased by reference, the parameter is, itself, a reference to an existent object and will not be temporary in the scope of the function call.

Adelbert answered 18/12, 2023 at 11:47 Comment(2)
Temporary object is a technical term in the ISO C++ standard. It may be that Stroustrup used the term first in a less formal meaning, but the question is whether or not the standard formally defines function parameter objects to also be temporary objects or not, which is in principle independent of any lifetime questions. The lifetime of function parameter objects is handled in a specific clause in the standard, separate from the clauses specifying temporary object lifetime, anyway. (Btw. it is implementation-defined whether they are destroyed on return. They may live longer.)Onanism
There is also the additional complication pre-C++17 that formally a call to a function with by-value parameter always creates another temporary object separate from the function parameter object, from which the latter is initialized in function parameter copy-initialization. Only when (optional) copy elision was applied, was this temporary object merged with the function parameter object, but then the question remains whether only the old object was a temporary object or whether the function parameter object itself is also.Onanism

© 2022 - 2024 — McMap. All rights reserved.