Lets take two structs/classes
struct C1{
C1(){};
C1(C1&){std::cout<<"copy"<<std::endl;}
C1(C1&&){std::cout<<"move"<<std::endl;}};
struct C2{
C1 c;
C2(){};
C1 get1(){return c;}
C1 get2(){return std::move(c);}};
And than
C1 a1=C2().c;
C1 a2=C2().get1();
C1 a3=C2().get2();
the output is
move
copy
move
Question
We know that members of rvalues are rvalues themselves. This is why with a1, the move constructor is called. Why than, is the copy constructor called in the case of a2. We are returning an rvalue from a function.
To put it differently, std::move casts to an rvalue. But, as a member of an rvalue, c, is already an rvalue. Why than is there a difference between the behavior with a2 and a3?
Good question. The dull answer is that there's just no no rule in the C++ spec that says that returning a member from a dying object like this automatically moves it.
You may be interested in what's called rvalue reference to this. It let's you overload on && and & such that you can manually implement the behaviour you expected:
struct C2{
C1 c;
C2(){};
C1 get1() & { std::cout << "&" << std::endl; return c;}
C1 get1() && { std::cout << "&&" << std::endl; return std::move(c);}
C1 get2(){return std::move(c);}
};
Now
C1 a2=C2().get1();
prints
&&
move
Cool, but quite rare.
Related:
What is "rvalue reference for *this"?
Is a member of an rvalue structure an rvalue or lvalue?
We know that members of rvalues are rvalues themselves.
Yes this is true, as states [expr.ref]/4.2 (emphasis mine):
If E2 is a non-static data member and the type of E1 is “cq1 vq1 X”, and the type of E2 is “cq2 vq2 T”, the expression designates the named member of the object designated by the first expression. If E1 is an lvalue, then E1.E2 is an lvalue; otherwise E1.E2 is an xvalue. Let the notation vq12 stand for the “union” of vq1 and vq2; that is, if vq1 or vq2 is volatile, then vq12 is volatile. Similarly, let the notation cq12 stand for the “union” of cq1 and cq2; that is, if cq1 or cq2 is const, then cq12 is const. If E2 is declared to be a mutable member, then the type of E1.E2 is “vq12 T”. If E2 is not declared to be a mutable member, then the type of E1.E2 is “cq12 vq12 T”.
And also, from [expr.ref]/4.5:
If E2 is a member enumerator and the type of E2 is T, the expression E1.E2 is a prvalue. The type of E1.E2 is T.
So far so good. You can only get an lvalue if E1 is an lvalue itself, otherwise it's an xvalue or a prvalue.
But, as a member of an rvalue, c, is already an rvalue.
This is where your assumptions are wrong.
From [class.this]/1 (emphasis mine)
In the body of a non-static (9.3) member function, the keyword this is a prvalue expression whose value
is the address of the object for which the function is called. The type of this in a member function of
a class X is X*.
this is a prvalue of type X*, and dereferencing a pointer of type X yield an lvalue of type X.
Since accessing a member inside a member function is equivalent to (*this).m, then m is accessed through an lvalue of type X.
So your code is equivalent to:
C1 get1() { return (*this).c; }
// lvalue ----^ ^--- must be an lvalue too then.
Since this is always the same type, then even when using a function ref-qualifier the expression c inside a member function will always be an lvalue:
C1 get1() && { return (*this).c; }
// ^---- lvalue again, accessing through a pointer
Related
struct Test{
Test(int& v):rf(v){}
int& rf;
int obj;
};
int main(){
int i = 0;
Test t{i};
t.rf = 1;
t.obj = 1;
}
According to these rules for class member access:
If E2 is declared to have type “reference to T”, then E1.E2 is an lvalue; the type of E1.E2 is T. Otherwise, one of the following rules applies.
The clause only says what value category and type the expression are when E2 is of reference type. It's unlike these clauses that apply for the expression E1.E2, where E2 is not of reference type. which discuss what the entity denoted by such an expression implicitly. Such as:
If E2 is a static data member and the type of E2 is T, then E1.E2 is an lvalue; the expression designates the named member of the class.
If E2 is a non-static data member and the type of E1 is “cq1 vq1 X”, and the type of E2 is “cq2 vq2 T”, the expression designates the named member of the object designated by the first expression.
If it refers to a static member function and the type of E2 is “function of parameter-type-list returning T”, then E1.E2 is an lvalue; the expression designates the static member function.
Otherwise, if E1.E2 refers to a non-static member function and the type of E2 is “function of parameter-type-list cv ref-qualifier opt
returning T”, then E1.E2 is a prvalue. The expression designates a non-static member function.
The section [expr.ref] says all the situations that what the entity denoted by E1.E2 except that when E2 is of reference type.
basic.lval#2
The result of a glvalue is the entity denoted by the expression.
Such as t.obj, Because obj is a non-static non-reference data member(one of the following rules applies, the expression designates the named member of the object designated by the first expression), hence The entity denoted by the expression t.obj is the member obj of the object t, namely the subobject obj within t, So the result of such lvalue is such an entity.
However, For the example t.rf, there's no any quote in [expr.ref] points out what's the entity denoted by this expression? when applying assignment operation to such lvalue t.rf = 1;, t.rf as a glvalue, which should be determined which entity it denotes, then the right operand will modify the value of the entity. So, My question is:
what's the entity the expression t.rf denotes, which rule in the standard says that?
According to [expr.ref]/(4.2) and the fact that A() is a prvalue, we conclude that A().a[0] is an xvalue. See highlighted sentence below.
If E2 is a non-static data member and the type of E1 is “cq1 vq1 X”,
and the type of E2 is “cq2 vq2 T”, the expression designates the named
member of the object designated by the first expression. If E1 is an
lvalue, then E1.E2 is an lvalue; otherwise E1.E2 is an xvalue. Let the
notation vq12 stand for the “union” of vq1 and vq2; that is, if vq1 or
vq2 is volatile, then vq12 is volatile. Similarly, let the notation
cq12 stand for the “union” of cq1 and cq2; that is, if cq1 or cq2 is
const, then cq12 is const. If E2 is declared to be a mutable member,
then the type of E1.E2 is “vq12 T”. If E2 is not declared to be a
mutable member, then the type of E1.E2 is “cq12 vq12 T.
Therefore the snippet below should compile. The code doesn't compile in GCC, neither in VS2017, but it compiles in clang.
#include<iostream>
struct A
{
int a[3];
A(): a{1, 2, 3} {}
};
int main()
{
int &&r = A().a[0];
std::cout << r << '\n';
}
However, the wording in [expr.sub]/1 indicates that a[0] is an lvalue, irrespective of the value category of A(), and that seems to be incorrect to me.
A postfix expression followed by an expression in square brackets is a
postfix expression. One of the expressions shall be a glvalue of type
“array of T” or a prvalue of type “pointer to T” and the other shall
be a prvalue of unscoped enumeration or integral type. The result is
of type “T”. The type “T” shall be a completely-defined object type.66
The expression E1[E2] is identical (by definition) to *((E1)+(E2)) [
Note: see 8.5.2 and 8.5.6 for details of * and + and 11.3.4 for
details of arrays. —end note ] , except that in the case of an array
operand, the result is an lvalue if that operand is an lvalue and an
xvalue otherwise. The expression E1 is sequenced before the expression
E2.
There is no contradiction, you're just parsing the expression wrongly. If I understand you correctly, you're saying that E1 is A() and E2 is a[0] which is not the case.
In fact, E2 is a. Because . and [] have the same precedence, the expression is parsed as (A().a)[0].
This means that according to [expr.ref]p4.2, A().a is an xvalue (of array type), and so that per [expr.sub]p1 (A().a)[0] is thus an xvalue.
Assuming a class A has a member variable(which is an object rather than a reference) m. Naturally I will think that:
When I defined an object 'o1', then the Expression 'o1.m' is an object type either;
When I defined a reference 'q1', then the Expression 'q1.m' is a reference type either.
Is that conclusion correct? I'm wondering what any relative clauses are in C++ standard document if it is true(I've been searching for it/them for one more days already but got almost all about 'reference as member of class' so far)?
Take a look at §5.2.5 (Class member access in Postfix Expressions, from N3797 C++14 Draft):
Abbreviating postfix-expression.id-expression as E1.E2, E1 is called the object expression. The type and value category of E1.E2 are determined as follows. In the remainder of 5.2.5, cq represents either const or the absence of const and vq represents either volatile or the absence of volatile. cv represents an
arbitrary set of cv-qualifiers, as defined in 3.9.3.
If E2 is declared to have type “reference to T,” then E1.E2 is an lvalue; the type of E1.E2 is T. Otherwise,
one of the following rules applies.
If E2 is a non-static data member and the type of E1 is “cq1 vq1 X”, and the type of E2 is “cq2 vq2 T”, the expression designates the named member of the object designated by the first expression. If E1 is an lvalue, then E1.E2 is an lvalue; otherwise E1.E2 is an xvalue. Let the notation vq12 stand for the “union” of vq1 and vq2 ; that is, if vq1 or vq2 is volatile, then vq12 is volatile. Similarly, let the notation cq12 stand for the “union” of cq1 and cq2 ; that is, if cq1 or cq2 is const, then cq12 is const. If E2 is declared to be a mutable member, then the type of E1.E2 is “vq12 T”. If E2 is not declared to be a mutable member, then the type of E1.E2 is “cq12 vq12 T”.
The standard says nothing about E2 becoming a reference even if E1 is. To be explicit, if E1 is a reference type and E2 is not, E1.E2 is not a reference type.
The Standard provide the following note:
[ Note: it is not possible to use a pointer to member that refers to a
mutable member to modify a const class object. For example,
struct S {
S() : i(0) { }
mutable int i;
};
void f()
{
const S cs;
int S::* pm = &S::i; // pm refers to mutable member S::i
cs.*pm = 88; // ill-formed: cs is a const object
}
-end note]
But we can use just object-expression to modify const object which has a mutale data member.
#include <iostream>
struct A
{
A(){ }
mutable int a;
};
const A a;
int main()
{
a.a = 4;
std::cout << a.a; //4
}
DEMO
But ISO/IEC Derictive tells
Notes and examples integrated in the text of a document shall only be
used for giving additional information intended to assist the
understanding or use of the document. They shall not contain
requirements ("shall"; see 3.3.1 and Table H.1) or any information
considered indispensable for the use of the document [...]
Which means the note I provide at the beginning of my Q is not a requirement.
I'm looking for a normative requirement explcitly precludes such using.
Just before that note you will find the following:
The restrictions on cv-qualification, and the manner in which the cv-qualifiers of the operands are combined to produce the cv-qualifiers of the result, are the same as the rules for E1.E2 given in 5.2.5
Jump up to 5.2.5 and you'll find this:
If E2 is a non-static data member and the type of E1 is “cq1 vq1 X”, and the type of E2 is “cq2 vq2 T”, the expression designates the named member of the object designated by the first expression. If E1 is an lvalue, then E1.E2 is an lvalue; otherwise E1.E2 is an xvalue. Let the notation vq12 stand for the “union” of vq1 and vq2; that is, if vq1 or vq2 is volatile, then vq12 is volatile. Similarly, let the notation cq12 stand for the “union” of cq1 and cq2; that is, if cq1 or cq2 is const, then cq12 is const. If E2 is declared to be a mutable member, then the type of E1.E2 is “vq12 T”. If E2 is not declared to be a mutable member, then the type of E1.E2 is “cq12 vq12 T”.
The union of the const qualifiers in cs.*pm is const, the exception for mutable members doesn't apply to pointers.
It's easier to understand if you consider that storage class specifiers are not part of the type, so how would the compiler be able to distinguish between mutable and non-mutable pointers to member?
struct S;
void f(const S& s, int S::* pm)
{
s.*pm = 1; // How do I know if pm points to a mutable member? S isn't even defined!
}
Simply put, there is no such thing as a pointer to a mutable member, just as there is no such thing as a pointer to a static member, the pointed type's storage class is unknown (the type can only be qualified by const and / or volatile).
The code is as following:
struct A
{
static int k;
int i;
};
int A::k = 10;
A func() { A a; return a; }
My question is, how can I tell whether func().k or func().i is an lvalue or not? If both are lvalues/rvalues, how can I test them?
func().k = 0; // compile ok under g++-4.4 and g++-4.6
func().i = 1; // compile ok with g++-4.4, but g++-4.4 gives an error:
//"using temporary as lvalue [-fpermissive]"
func().k is an lvalue and func().i is an xvalue.
You can see this for more details:
rvalues and temporary objects in the FCD
Althrough, it is not difficult to test whether they are lvalues or rvalues:
#include <iostream>
struct A
{
static int k;
int i;
};
int A::k = 10;
A func( ){ A a; return a; }
void f (int & ) { std::cout << "int& " << std::endl; }
int main ()
{
func().k = 0; //ok, because func().k is an r
f(func().k);
func().i = 1; //compile error: "using temporary as lvalue"
f(func().i); //compile error because func().i is an rvalue of type ‘int’
return 0;
}
"Assignability" isn't a good test for lvalueness as we can have non-mutable lvalues (e.g. const reference expressions) and assignment may be a member function call which can be made on an rvalue of class type.
You have to refer to the standard (ISO/IEC 14882:2011).
5.2.2/10: A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.
So func() is a prvalue.
5.2.5/4: If E2 is declared to have type "reference to T," then E1.E2 is an lvalue; the type of E1.E2 is T. Otherwise, one of the following rules applies.
If E2 is a static data member and the type of E2 is T, then E1.E2 is an lvalue; the expression designates the named member of the class. The type of E1.E2 is T`.
So func().k is an lvalue.
If E2 is a non-static data member and the type of E1 is "cq1 vq1 X", and the type of E2 is "cq2 vq2 T", the expression designates the named member of the object designated by the first expression. If E1 is an lvalue, then E1.E2 is an lvalue; if E1 is an xvalue, then E1.E2 is an xvalue; otherwise, it is a prvalue. [...]
So func().i is a prvalue.
There is no need to actually "test" whether a given value is an lvalue or an rvalue.
Etymologically/Historically, an lvalue is what is on the left side of the assigment operator, and an rvalue what is on the right side. (This definition is not exactly correct though.) Note that rvalues can be lvalues.
Simple rule of thumb: If you can take its address, it's an lvalue. However, in C++11 there are rvalue references which makes things not that simple. So the rule is more like: if you can take its address using &.
Maybe some examples will clear things up:
int a = 5; // a is an lvalue, 5 is an rvalue
int b = fun(); // fun is an rvalue
fun() = a; // illegal, can't assign to an rvalue (suppose foo returns int)
See http://en.wikipedia.org/wiki/Value_%28computer_science%29 for more.
I am not sure what exactly you are trying to achieve but as you are allocating memory within scope of function() returning that object. This object goes out of scope once the call to function() returns and hence it can be freed by the compiler. You can face a lot of troubles in later phases. I think you need to redesign the problem solution.