发信人: eastcrusader (昨我已逝), 信区: CPlusPlus
标 题: [合集] 一个返回非引用的函数可以如此放在 = 左边吗?
发信站: 水木社区 (Wed Dec 28 11:35:31 2005), 站内
☆─────────────────────────────────────☆
AN0 (chaos,快回书架上来!) 于 (Wed Dec 21 00:08:09 2005) 提到:
int f();
f()=1; //这个不行,编译器提示不是lvalue,应该是因为返回的是tmp吧?
class X {};
X g();
g() = X(); //这个为什么可以?效果是什么?
☆─────────────────────────────────────☆
Angelo23 (海啸 海笑) 于 (Wed Dec 21 04:15:41 2005) 提到:
第二个貌似和NRVO有关吧
【 在 AN0 (chaos,快回书架上来!) 的大作中提到: 】
: int f();
: f()=1; //这个不行,编译器提示不是lvalue,应该是因为返回的是tmp吧?
: class X {};
: ...................
☆─────────────────────────────────────☆
longda (longda@admire) 于 (Wed Dec 21 09:54:16 2005) 提到:
这个是不是有点茴香了. 我想这个是因为自定义类型的assignment operator 不一定需要lvalue.
【 在 AN0 (chaos,快回书架上来!) 的大作中提到: 】
: int f();
: f()=1; //这个不行,编译器提示不是lvalue,应该是因为返回的是tmp吧?
: class X {};
: ...................
☆─────────────────────────────────────☆
jasss (robot) 于 (Wed Dec 21 13:44:54 2005) 提到:
【 在 AN0 (chaos,快回书架上来!) 的大作中提到: 】
: int f();
: f()=1; //这个不行,编译器提示不是lvalue,应该是因为返回的是tmp吧?
The result of calling a function that does not return a
reference is an rvalue, so here f() can not be put in left
hand side of = operator, which is not a function call...
: class X {};
: X g();
: g() = X(); //这个为什么可以?效果是什么?
Here g() is also a rvalue expression, but in your example it is
OK since invoking the assignment operator call (function call)
does not require a lvalue expression at all ...
☆─────────────────────────────────────☆
ilovecpp (cpp) 于 (Wed Dec 21 13:56:53 2005) 提到:
【 在 jasss (robot) 的大作中提到: 】
[snip]
: Here g() is also a rvalue expression, but in your example it is
: OK since invoking the assignment operator call (function call)
: does not require a lvalue expression at all ...
Seems this is the only place you can obtain a pointer (this)
to a rvalue. A little strange.
Put it another way:
struct S {
void f();
};
void g(S&);
void S::f() { g(*this); }
void h() {
h(S()); // Error
S().f(); // Ok... an extra level of indirection makes wonders...
}
☆─────────────────────────────────────☆
jasss (robot) 于 (Wed Dec 21 15:22:10 2005) 提到:
【 在 ilovecpp (cpp) 的大作中提到: 】
: [snip]
: Seems this is the only place you can obtain a pointer (this)
: to a rvalue. A little strange.
:
Well, for an non-const rvalue, you can even call the
non-const member function for that object ... That means,
you can even *change* the rvalue if you want. Therefore,
obtaining the "this" pointer is not so strange compared
with these behaviors in my mind... :)
Although we share the same feeling for this issue, it would
be unacceptable if we remove this rule, since almost we
can not live without this behavior ...
☆─────────────────────────────────────☆
AN0 (chaos,快回书架上来!) 于 (Thu Dec 22 00:13:03 2005) 提到:
3x.
Your explanation is very clear and acceptable.
However, I am wondering about why the operator[] of bitset returns by value
instead of by reference(note the value type itself is "reference"), that we
can not use it to set the bit.
【 在 jasss (robot) 的大作中提到: 】
: The result of calling a function that does not return a
: reference is an rvalue, so here f() can not be put in left
: hand side of = operator, which is not a function call...
: ...................
☆─────────────────────────────────────☆
cygwin (没有呢称了) 于 (Thu Dec 22 00:20:09 2005) 提到:
我一直以为rvalue是不能改变的,
既然可变
那rvalue的意义?
【 在 jasss (robot) 的大作中提到: 】
: Well, for an non-const rvalue, you can even call the
: non-const member function for that object ... That means,
: you can even *change* the rvalue if you want. Therefore,
: ...................
☆─────────────────────────────────────☆
jasss (robot) 于 (Thu Dec 22 12:10:43 2005) 提到:
【 在 cygwin (没有呢称了) 的大作中提到: 】
: 我一直以为rvalue是不能改变的,
: 既然可变
: 那rvalue的意义?
Again, I can also understand your feeling here, but rvalue is
really modifiable in my mind.
Yes, this topic is always confusing, especially for the one who
came from C's world, myself is a good example. But I will try
to explain it a little bit more...
C++ language borrows the name "lvalue" from C language, and
the C++ std says (3.10) :
1 Every expression is either an lvalue or an rvalue.
2 An lvalue refers to an object or function. [snip]
Here to understand what is lvalue, we must understand what is
"object". In std 1.8 we see that:
An object is a region of storage. [Note: A function is not an
object, regardless of whether or not it occupies storage in the
way that objects do. ] An object is created by a definition (3.1),
by a new-expression (5.3.4) or by the implementation (12.2) when
needed.
Understand what is object is very important since we use this
concept almost everywhere. For example:
int i = 1; // Here number 1 is object or not?
int &r = i; // Here reference r is object or not?
//please think about it. I will answer it later (#).
If we get what is object, then, here everything should be very
clear for lvalue. Given a lvalue, we know that we can get its
address, since it *is* an object or function. And, for object
we can get the actual value, which is contained by that object.
And, from the above definitions, we see that:
1. Some lvalues are modifiable, since they are object.
2. Some lvalues are not modifiable. For example, array is
a lvalue, but you can not change it(its name, not element).
This is also true for function, and const lvalue is also
unmodifiable.
C++'s rvalue is a little bit more complex. Actually in C language
there is no such a concept at all(Only lvalue and non-lvalue).
The reason why C++ introducing rvalue is, well, we need member
function call. Let's see it...
In the same section (3.10), the std says:
2. ...[snip]
Some rvalue expressions -- those of class or cv-qualified
class type -- also refer to objects.
Here, to be simple, we can think the rvalue expression object
is just "temporary class type object".
Q1: Why object is necessary here?
A1: Because we need the "this pointer" to call a member
function. No object, no this pointer ...
Q2: Then why member function call necessary here?
A2: Because without this rule, instead of just write:
singleton::get_instance()->mem_fun();
// you can find longer delegations
we must write something like this:
singleton *p = singleton::get_instance();
p->mem_fun();
unacceptable, right?
Q3: Do we have non-class type rvalue expression refers to
object?
A3: No, non-class type rvalue expression does not refer
to any object, it just provide your a "value", and
usually should only be used for assignment expression.
And now lets go back to see whether rvalue is modifiable or not.
From above rule, I read that since rvalue expression can also
refer to class type object, then it is modifiable.
Several other words for lvalue&rvalue:
1 Some built-in operators expect lvalue operands. For example,
built-in assignment operators all expect their left hand
operands to be lvalues, so you cannot write:
int i = 1;
2 = i; // error, 2 is not a lvalue
2 The result of calling a function that does not return a
reference is an rvalue. User defined operators are functions,
and whether such operators expect or yield lvalues is determined
by their parameter and return types. Therefore:
int f();
f() = 1; // error, expect lvalue but f() yields rvlaue
class_foo g();
g() = obj_foo; // ok, does not expect lvalue
3 No all lvalues can be changed.
4 Some rvalues can be changed.
5 If you feel strange about the naming of lvalue&rvalue,
then you are not alone. :)
(left-hand-size, and right-hand-side are not
very accurate in our C++ context)
(#)Answer:
They are value, alias, but they are not objects.
☆─────────────────────────────────────☆
jasss (robot) 于 (Thu Dec 22 12:16:03 2005) 提到:
【 在 AN0 (chaos,快回书架上来!) 的大作中提到: 】
: However, I am wondering about why the operator[] of bitset returns by
: value instead of by reference(note the value type itself is "reference"),
: that we can not use it to set the bit.
Well, actually for subscript operators it is common that we have
two forms :
1. T const &operator [](size_t index) const;
2. T &operator [](size_t index);
for different contexts ...
Use the second one if you want to change the actual content ...
☆─────────────────────────────────────☆
AN0 (chaos,快回书架上来!) 于 (Thu Dec 22 16:26:51 2005) 提到:
yes, I know that, and in fact, I expect that to happen with "bitset"(the std container); but, the operator[] of "bitset" returns a *value* whose type is "reference", not a *reference* to "reference" as we had ordinarily expected.
I am wondering why?
Can you give me some hints?
3x very much:)
【 在 jasss (robot) 的大作中提到: 】
: Well, actually for subscript operators it is common that we have
: two forms :
: 1. T const &operator [](size_t index) const;
: ...................
☆─────────────────────────────────────☆
cygwin (没有呢称了) 于 (Thu Dec 22 18:59:51 2005) 提到:
2 An lvalue refers to an object or function. [snip]
int i;
i = 3;
u said that i is not an object,and we know
i is not a function , then is i here a lvalue ?
I think it is, so I'm confused.
【 在 jasss (robot) 的大作中提到: 】
: Again, I can also understand your feeling here, but rvalue is
: really modifiable in my mind.
: Yes, this topic is always confusing, especially for the one who
: ...................
☆─────────────────────────────────────☆
fhboy (点点) 于 (Thu Dec 22 19:12:04 2005) 提到:
He didn't say that. He just said that '1' and 'r' weren't objects and of course 'i' is an object.
【 在 cygwin (没有呢称了) 的大作中提到: 】
: 2 An lvalue refers to an object or function. [snip]
: int i;
: i = 3;
: ...................
☆─────────────────────────────────────☆
cygwin (没有呢称了) 于 (Thu Dec 22 19:16:02 2005) 提到:
oh,i see
the question ask for 1 not i,
I misreaded that
【 在 fhboy (点点) 的大作中提到: 】
: He didn't say that. He just said that '1' and 'r' weren't objects and of course 'i' is an object.
☆─────────────────────────────────────☆
goer (不如歸去) 于 (Thu Dec 22 19:21:22 2005) 提到:
【 在 jasss (robot) 的大作中提到: 】
:: Q2: Then why member function call necessary here?
:
: A2: Because without this rule, instead of just write:
:
: singleton::get_instance()->mem_fun();
: // you can find longer delegations
: we must write something like this:
: singleton *p = singleton::get_instance();
: p->mem_fun();
: unacceptable, right?
我有个疑问啊!返回指针和返回引用的本质是一样的吧?
singleton::get_instance()->mem_fun();//这个和左右值无关吧?
: ...................-
西安事变,张无忌,杨不悔
天宝之乱,郭破虏,李莫愁
☆─────────────────────────────────────☆
fhboy (点点) 于 (Thu Dec 22 20:23:14 2005) 提到:
[snip]
: 2 The result of calling a function that does not return a
: reference is an rvalue. User defined operators are functions,
: and whether such operators expect or yield lvalues is determined
: by their parameter and return types. Therefore:
:
: int f();
: f() = 1; // error, expect lvalue but f() yields rvlaue
:
: class_foo g();
: g() = obj_foo; // ok, does not expect lvalue
:
[snip]
yeah, the author of 《thinking in c++》says that "the compiler already prevents the built-in type which is returned by value forme being an lavlue. Only when you're returning objects of user-defined types by value does it become an issue."
And here is the example:
class X
{
public:
void modify(){}
};
X f()
{
return X();
}
void ff(X&)
{
}
int main()
{
f().modify();//(1)
f() = X();//(2)
ff(f());//(3)
}
maybe (3) causes an error or a warning, but (1)(2) are legal! He says though in all cases the compiler creates temporary objects which are automatically const, the modifications of temporary objects in case (1)(2) are lost.
So I am just wondering how can a const object call a non-const member function no matter it is a lvalue or a rvalue?