I am trying to know whether a prvalue
is same as a temporary
in C 17. Consider the following example,
//C 17 example
#include <iostream>
struct Custom
{
Custom()
{
std::cout<<"default constructor called"<<std::endl;
}
Custom(const Custom& var)
{
std::cout<<"copy constructor called"<<std::endl;
}
~Custom()
{
std::cout<<"destructor called"<<std::endl;
}
};
Custom func()
{
Custom temp;
return temp;//this will use copy constructor
}
int main() {
func();
}
Assuming the above code is executed with the -fno-elide-constructors
options enabled, my question is whether the prvalue that is created as a copy of the local object named temp
inside the function func
is the same as a temporary in C 17.
I have read that in C 17, a prvalue is not an object. For example, here the user says that
"Prvalues are not objects (since C 17)".
Similarly, here the user says
"Before C 17 the prvalue was already the temporary, which is what your quote refers to. Since C 17 the prvalue itself is not a temporary..."
But that confused me because if an prvalue is not an object, then what is it? I mean, in the above example a copy of temp
is created using the copy constructor. Now, prior to C 17, that copy is a temporary object which is an prvalue. But what is changed in C 17. My thinking is that we still have an prvalue that is created using the copy constructor and that prvalue is a temporary in C 17 because it exists for some limited duration.
PS: I may be wrong in describing what is actually happening, so please correct me by explaining what is happening in C 17 and how is it different from C 14. I am also asking because i have read on SO posts(similar posts) that in the above example, there is no temporary involved in C 17 which i do not understand how it is possible.
CodePudding user response:
But that confused me because if an prvalue is not an object, then what is it?
An expression that can become an object.
My thinking is that we still have an prvalue that is created using the copy constructor and that prvalue is a temporary in C 17 because it exists for some limited duration.
The prvalue isn't an object yet (or thought of differently, here).
Let's extend your example by using func
to initialise something.
int main() {
auto obj = func();
}
obj
in main
and temp
in func
are "the same object". It is like if func
was instead
void func(Custom * result) {
Custom & temp = *new(result) Custom;
}
int main() {
char storage[sizeof(Custom)];
Custom & obj = *reinterpret_cast<Custom *>(storage);
func(&obj);
obj.~Custom();
}
Or with -fno-elide-constructors
leaving the copy of temp
into the return value:
void func(Custom * result) {
Custom temp;
new(result) Custom(temp);
}
What changed between C 14 to C 17 is instead of that being an permitted divergence from the behaviour of the abstract machine, the definition of the abstract machine was changed to have that behaviour.
CodePudding user response:
std::vector<int> func() {
std::vector<int> temp = {0, 1, 2, 3};
return temp;
}
int main() {
std::vector<int> vec = func(); // Copy temp and then delete temp
return 0;
}
Prvalue includes temporary values while evaluating expressions and non-reference return.
You may refer to this https://changkun.de/modern-cpp/en-us/03-runtime/#lvalue-rvalue-prvalue-xvalue