右值是不是只可以放在赋值运算符的右边,不可以放在左边?

李刚弄死他 2014-01-25 04:13:08
可不可以这样:

右值=11;
...全文
636 点赞 收藏 62
写回复
62 条回复
李刚弄死他 2014年02月17日
引用 60 楼 ALNG 的回复:
[quote=引用 41 楼 supermegaboy 的回复:] [quote=引用 40 楼 ALNG 的回复:] 这个问题的原因纯粹就是运算符重载是成员函数。 ========================================= 或者说,内建类型的赋值操作被语言标准(从而符合标准的编译器)要求必须为左值,而类的赋值运算符,哪怕是编译其合成的,却没有这样的要求。 那和我上面的理解有什么本质的差别吗?
有啊,你的着眼点是临时对象是否const、是否可修改的角度,但这个问题与是否可修改并无关系,C/C++并无将临时对象视作const,C和C++03只是没有提供修改内置类型右值的语言设施(C++11提供了右值引用,可以修改),并不表示将其视作const。不应该从这个角度去证明。 另外我觉得你的解释最大的问题还不是这里,而在于你试图用实现语义去解释赋值运算符重载这样的抽象语义,你会得出错误结论。[/quote] 早期的C++编译器(前标准时代)很多允许这样的语法的--对内间类型临时变量赋值。这个设施是有意拿掉的,因为它无实际意义。C/C++不追求纯粹,不会为了逻辑上的连贯性或看上去很美而不做与之相反的更实用或更有效的选择。比如我前面举过的多维数组的例子。[/quote] 内置类型的变量在语法上是允许被赋值的。
回复 点赞
李刚弄死他 2014年01月27日
早期的C++编译器(前标准时代)很多允许这样的语法的--对内间类型临时变量赋值。这个设施是有意拿掉的,因为它无实际意义。C/C++不追求纯粹,不会为了逻辑上的连贯性或看上去很美而不做与之相反的更实用或更有效的选择。比如我前面举过的多维数组的例子。[/quote] 你举过什么多维数组的例子?另外你见过哪些早期的C++编译器允许对内置类型的临时变量赋值?
回复 点赞
孩皮妞野 2014年01月27日
引用 41 楼 supermegaboy 的回复:
[quote=引用 40 楼 ALNG 的回复:] 这个问题的原因纯粹就是运算符重载是成员函数。 ========================================= 或者说,内建类型的赋值操作被语言标准(从而符合标准的编译器)要求必须为左值,而类的赋值运算符,哪怕是编译其合成的,却没有这样的要求。 那和我上面的理解有什么本质的差别吗?
有啊,你的着眼点是临时对象是否const、是否可修改的角度,但这个问题与是否可修改并无关系,C/C++并无将临时对象视作const,C和C++03只是没有提供修改内置类型右值的语言设施(C++11提供了右值引用,可以修改),并不表示将其视作const。不应该从这个角度去证明。 另外我觉得你的解释最大的问题还不是这里,而在于你试图用实现语义去解释赋值运算符重载这样的抽象语义,你会得出错误结论。[/quote] 早期的C++编译器(前标准时代)很多允许这样的语法的--对内间类型临时变量赋值。这个设施是有意拿掉的,因为它无实际意义。C/C++不追求纯粹,不会为了逻辑上的连贯性或看上去很美而不做与之相反的更实用或更有效的选择。比如我前面举过的多维数组的例子。
回复 点赞
飞天御剑流 2014年01月26日
引用 26 楼 ALNG 的回复:
这是一个很好的质疑,C++在这里的处理逻辑并不连贯。对于内建类型,作为返回值的时候,相当于其前面加了个const限定符。这是一种特殊处理,与临时变量的左右值性没有太大关联。或者说内建类型的临时变量相当于有一个const限定符。而对自定义类型的临时对象,编译器并不自动加上这个限定,你可以对这个临时变量使用所有非const的成员函数(更不用说const成员函数了), 包括operator =(), 如果你定义了一个或者编译器可以帮你合成一个的话。因为可以断言,对内建类型的临时变量的修改没有任何实际价值,而发生这类情况的通常是一个错误,比如==写成=了,所以编译器的这种逻辑不连贯的特殊处理有应用价值。 类似的像 int array[5][3]; 在array[5]指向的地方并没有一个实际的int*, 把array传给一个需要int **的函数它就要露馅了。但继承自C的这种特殊处理虽然让逻辑上不那么连贯,但确实在特定的情形下可以在不失表达清晰的情况下让内存的使用更经济(否则就要 int array[15]; array[i*5+j]=10; 比之 array[i][j]=10, 当然后者更好读)。这类特殊处理有实用价值,值得牺牲商量的逻辑上的连贯性。 这是我的理解,没有权威的标准文本作支持,仅供参考。
不对。
回复 点赞
孩皮妞野 2014年01月26日

struct S
{
};

S Sfunc()
{
	return S();
}

const int func()
{
	return 5;
}


template <class T>
struct const_modified{
    const static bool value=0;
};

tempalte <class T>
struct const_modified<const T>{
    const static bool value=1;
};

int main()
{
	const_modified<Sfunc()>::value;
	const_modified<func()>::value
}
引用 24 楼 u011774561 的回复:
[quote=引用 23 楼 mujiok2003 的回复:] [quote=引用 22 楼 u011774561 的回复:] [quote=引用 21 楼 mujiok2003 的回复:] 左值右值和能不能出现在等号左边没有关系.
咱不提等号,我也没说是否和等号有关系,你来看这个程序: int t; int func() { return t; } func()=1; func()现在返回的是右值的吧,为什么func()=1不可以了,而返回一个对象就可以呢?这是怎么回事?临时对象可以放在左边,而临时的内置变量不可以。[/quote] 因为自定义类型重载了operator =[/quote] 内置类型也有=运算符啊,并且可以轻松地进行赋值操作啊,没有什么问题啊,为什么不可以将一个值赋给一个临时的变量呢,而赋给一个非临时变量就可以呢?[/quote] 这是一个很好的质疑,C++在这里的处理逻辑并不连贯。对于内建类型,作为返回值的时候,相当于其前面加了个const限定符。这是一种特殊处理,与临时变量的左右值性没有太大关联。或者说内建类型的临时变量相当于有一个const限定符。而对自定义类型的临时对象,编译器并不自动加上这个限定,你可以对这个临时变量使用所有非const的成员函数(更不用说const成员函数了), 包括operator =(), 如果你定义了一个或者编译器可以帮你合成一个的话。因为可以断言,对内建类型的临时变量的修改没有任何实际价值,而发生这类情况的通常是一个错误,比如==写成=了,所以编译器的这种逻辑不连贯的特殊处理有应用价值。 类似的像 int array[5][3]; 在array[5]指向的地方并没有一个实际的int*, 把array传给一个需要int **的函数它就要露馅了。但继承自C的这种特殊处理虽然让逻辑上不那么连贯,但确实在特定的情形下可以在不失表达清晰的情况下让内存的使用更经济(否则就要 int array[15]; array[i*5+j]=10; 比之 array[i][j]=10, 当然后者更好读)。这类特殊处理有实用价值,值得牺牲商量的逻辑上的连贯性。 这是我的理解,没有权威的标准文本作支持,仅供参考。
回复 点赞
孩皮妞野 2014年01月26日
这个问题的原因纯粹就是运算符重载是成员函数。 ========================================= 或者说,内建类型的赋值操作被语言标准(从而符合标准的编译器)要求必须为左值,而类的赋值运算符,哪怕是编译其合成的,却没有这样的要求。 那和我上面的理解有什么本质的差别吗?
回复 点赞
赵4老师 2014年01月26日
不要纠结左值右值了,这个世界上唯一不变的就是变化。用API WriteProcessMemory还能修改正运行的其它进程的内存里面的所谓左值右值呢! http://bbs.csdn.net/topics/390627329
#pragma comment(linker,"/SECTION:.text,RW")
#include <stdio.h>
#ifdef _DEBUG
#define OFFSET 0x0C
#else
#define OFFSET 0x01
#endif
int *p;
int p2() {
    int a;
 
    a=2;
    return a;
}
int main() {
    p=(int *)((char *)p2+OFFSET);
    printf("p2==0x%08x,p==0x%08x,*p==%d\n",(char *)p2,p,*p);
    *p=3;
    printf("p2()==%d\n",p2());
    return 0;
}
//p2==0x00401000,p==0x0040100c,*p==2
//p2()==3
//
请问a=2;中的右值2咋还能被改变呢?
回复 点赞
孩皮妞野 2014年01月26日
引用 30 楼 u011774561 的回复:
[quote=引用 29 楼 supermegaboy 的回复:] [quote=引用 28 楼 ALNG 的回复:] 那你解释一下


int I()
{
    return 5;
}

struct S{};
S _S()
{
    return S();
}

int main()
{
     I()=3;  // a compiler error WRT lvalue
     _S()=S(); // this line compile fine
}
都是临时变量,为什么内建类型的不可以被赋值而自定义类型的就可以?
你想多了,其实原因非常简单,甚至与左右值无关,你们只不过被=的抽象形式及其使用习惯给迷惑了。 真正原因是:赋值运算符重载是成员函数,当你写S()=X的时候,它其实是S().operator=( X ),而成员函数是允许在右值上调用的。打完收工,就这么简单。 当然,这会产生一些问题,例如,由于赋值运算符重载通常按照内置赋值运算符的要求返回一个左值,会让如下代码成为合法: S &s = ( S() = S() ); 众所周知,当上述语句结束后,s所绑定的对象无法保证继续存在。 针对类似问题,C++11增加了引用限定符(ref-qualifier)去解决,例如在C++11中,可以如下声明赋值运算符重载: S& operator=( const S & ) &; //ref-qualifier S operator=( const S & ) &&; //ref-qualifier 当*this是右值时,返回一个右值。[/quote] 你这个说法不细致,正确的说法是:当按值返回一个内置类型时,它返回的是一个值,而不是变量,值是常量,比如说1、2、3这样的值,你怎么修改它?你将2赋给2,这可行吗?所以说错误。 但是当按值返回一个对象时,就不同了,因为对象的值就是对象,它不可能是个常量,要按值返回一个对象,那肯定是要调用复制构造函数的,复制完成后的对象怎么可能是个常量呢,除非你修改返回类型,所以不会报错。[/quote] 赞同一下。这个也和我上面说的对内建返回类型的临时变量编译器会把它处理成视同带了个const修饰符相佐证。但是1,2,3这样的常量值可以固化在程序代码中,函数的返回结果是动态的,它也许经编译器优化完全不通过内存(除非你的const int& p=func()一类的操作迫使编译器为它在堆栈上安排实际的存储---观测行为本身改变了其运动状态),但想想从前的内存器变量不也是可以读写的吗?所以我认为这里的本质区别不在它是值还是变量,而是编译器为这些内建类型的临时变量自动加了个const修饰符。
回复 点赞
赵4老师 2014年01月26日
引用 36 楼 supermegaboy 的回复:
[quote=引用 32 楼 zhao4zhong1 的回复:] 建议将“左值”和“右值”这两个概念从脑子中清除掉。
你有这个想法非常自然,因为你完全符合linus所称的垃圾程序员的范畴。这些人通常对于自己搞不懂的东西,就认为应该清除掉,因为C++有很多东西自己搞不明白,所以C++是垃圾语言。[/quote] 地球生态系统无法支持一种无所不能的动物,最后只好将它清除掉了。
回复 点赞
飞天御剑流 2014年01月26日
引用 32 楼 zhao4zhong1 的回复:
建议将“左值”和“右值”这两个概念从脑子中清除掉。
你有这个想法非常自然,因为你完全符合linus所称的垃圾程序员的范畴。这些人通常对于自己搞不懂的东西,就认为应该清除掉,因为C++有很多东西自己搞不明白,所以C++是垃圾语言。
回复 点赞
飞天御剑流 2014年01月26日
引用 31 楼 u011774561 的回复:
为了证实这一点,我专门测试了一下,我们知道,语法是允许这样的: int y=3; int &x=y; //y是个变量,所以可以用x来引用 但是如果这样: int x=2; int f() //在这里加个&就可以了 { return x; //现在返回的不是临时变量了 } int &x=f(); //f返回的不是变量,而是变量的值,所以不能用x来引用 我们知道要引用一个常量,必须用const,所以我再加上const: int const&x=f(); 这样就OK,这不是反过来证明按值返回一个内置类型,返回的是个值,而不是变量它自身吗,如果你想要返回变量自身,那你就要按引用来返回它。
当function returning type是reference时,函数调用后缀表达式属于左值表达式,这是基础知识。
回复 点赞
飞天御剑流 2014年01月26日
引用 30 楼 u011774561 的回复:
你这个说法不细致,正确的说法是:当按值返回一个内置类型时,它返回的是一个值,而不是变量,值是常量,比如说1、2、3这样的值,你怎么修改它?你将2赋给2,这可行吗?所以说错误。 但是当按值返回一个对象时,就不同了,因为对象的值就是对象,它不可能是个常量,要按值返回一个对象,那肯定是要调用复制构造函数的,复制完成后的对象怎么可能是个常量呢,除非你修改返回类型,所以不会报错。
这个问题并不能从值还是对象的角度去解释,因为按值返回的结果依然是一个对象,只不过是临时右值而已。你关于常量的理解也是不对的,C/C++中的常量并非指不会改变的量,而是字面量(C还要严格一点,要求编译期字面量)。函数的返回值不是常量。 这个问题的原因纯粹就是运算符重载是成员函数。
回复 点赞
李刚弄死他 2014年01月26日
引用 32 楼 zhao4zhong1 的回复:
建议将“左值”和“右值”这两个概念从脑子中清除掉。
你错了,要搞懂这些,必须先把左值和右值的概念彻底搞清楚,否则你脑子就一团糟,上面我写的如果你再搞不清楚左值和右值,那就别学了。
回复 点赞
李刚弄死他 2014年01月26日
引用 58 楼 mujiok2003 的回复:
[quote=引用 57 楼 u011774561 的回复:] [quote=引用 56 楼 mujiok2003 的回复:] [quote=引用 24 楼 u011774561 的回复:] 内置类型也有=运算符啊,并且可以轻松地进行赋值操作啊,没有什么问题啊,为什么不可以将一个值赋给一个临时的变量呢,而赋给一个非临时变量就可以呢?
引用
An rvalue should not be confused with the constness of an object. An rvalue does not mean the object would be immutable. There is some confusion about this, since non-class rvalues are non-modifiable. This is not the case with user types. A class rvalue can be used to modify an object through its member functions. Albeit in practice, it can be said that objects are modified only through modifiable lvalues. A modifiable lvalue is an lvalue that can be used to modify the object. Other lvalues are non-modifiable lvalues, const reference is a good example of this. As mentioned already, non-class rvalues do not have the same qualities as the user type rvalues. One might wonder about this. After all, C++ was designed so that user types would behave like built-ins, at least as uniformly as possible. Still this inconsistency exists and the reasons for it shall be explored later. Non-class rvalues are not modifiable, nor can have cv-qualified types (the cv-qualifications are ignored). On the contrary, the class rvalues are modifiable and can be used to modify an object via its member functions. They can also have cv-qualified types. In case of built-ins, some operators require an lvalue as does every assignment expression as the left side. The built-in address-of operator requires an lvalue which reflects the character of lvalues rather well.
具体看看这篇文章.[/quote] 这个文章就是把简单问题复杂化,其实就是一个内置类型的值与类类型的值的问题,你看他洋洋洒洒说了一大片,还是没个中心思想,问题的实质一点也没有说,都是泛泛而谈,真看不起这样的人。[/quote] 这篇文章不是为了回答你的问题写的,所以内容多了些. 做人要谦虚.[/quote] 不是谦虚不谦虚的问题,我看到写这样的又臭又长又没有内涵文章的人我就从心里感到恶心,既浪费别人的时间又浪费自己的时间,写这个文章的人又不是你,所以我没有针对你。
回复 点赞
赵4老师 2014年01月26日
建议将“左值”和“右值”这两个概念从脑子中清除掉。
回复 点赞
mujiok2003 2014年01月26日
引用 57 楼 u011774561 的回复:
[quote=引用 56 楼 mujiok2003 的回复:] [quote=引用 24 楼 u011774561 的回复:] 内置类型也有=运算符啊,并且可以轻松地进行赋值操作啊,没有什么问题啊,为什么不可以将一个值赋给一个临时的变量呢,而赋给一个非临时变量就可以呢?
引用
An rvalue should not be confused with the constness of an object. An rvalue does not mean the object would be immutable. There is some confusion about this, since non-class rvalues are non-modifiable. This is not the case with user types. A class rvalue can be used to modify an object through its member functions. Albeit in practice, it can be said that objects are modified only through modifiable lvalues. A modifiable lvalue is an lvalue that can be used to modify the object. Other lvalues are non-modifiable lvalues, const reference is a good example of this. As mentioned already, non-class rvalues do not have the same qualities as the user type rvalues. One might wonder about this. After all, C++ was designed so that user types would behave like built-ins, at least as uniformly as possible. Still this inconsistency exists and the reasons for it shall be explored later. Non-class rvalues are not modifiable, nor can have cv-qualified types (the cv-qualifications are ignored). On the contrary, the class rvalues are modifiable and can be used to modify an object via its member functions. They can also have cv-qualified types. In case of built-ins, some operators require an lvalue as does every assignment expression as the left side. The built-in address-of operator requires an lvalue which reflects the character of lvalues rather well.
具体看看这篇文章.[/quote] 这个文章就是把简单问题复杂化,其实就是一个内置类型的值与类类型的值的问题,你看他洋洋洒洒说了一大片,还是没个中心思想,问题的实质一点也没有说,都是泛泛而谈,真看不起这样的人。[/quote] 这篇文章不是为了回答你的问题写的,所以内容多了些. 做人要谦虚.
回复 点赞
李刚弄死他 2014年01月26日
引用 29 楼 supermegaboy 的回复:
[quote=引用 28 楼 ALNG 的回复:] 那你解释一下


int I()
{
    return 5;
}

struct S{};
S _S()
{
    return S();
}

int main()
{
     I()=3;  // a compiler error WRT lvalue
     _S()=S(); // this line compile fine
}
都是临时变量,为什么内建类型的不可以被赋值而自定义类型的就可以?
你想多了,其实原因非常简单,甚至与左右值无关,你们只不过被=的抽象形式及其使用习惯给迷惑了。 真正原因是:赋值运算符重载是成员函数,当你写S()=X的时候,它其实是S().operator=( X ),而成员函数是允许在右值上调用的。打完收工,就这么简单。 当然,这会产生一些问题,例如,由于赋值运算符重载通常按照内置赋值运算符的要求返回一个左值,会让如下代码成为合法: S &s = ( S() = S() ); 众所周知,当上述语句结束后,s所绑定的对象无法保证继续存在。 针对类似问题,C++11增加了引用限定符(ref-qualifier)去解决,例如在C++11中,可以如下声明赋值运算符重载: S& operator=( const S & ) &; //ref-qualifier S operator=( const S & ) &&; //ref-qualifier 当*this是右值时,返回一个右值。[/quote] 为了证实这一点,我专门测试了一下,我们知道,语法是允许这样的: int y=3; int &x=y; //y是个变量,所以可以用x来引用 但是如果这样: int x=2; int f() //在这里加个&就可以了 { return x; //现在返回的不是临时变量了 } int &x=f(); //f返回的不是变量,而是变量的值,所以不能用x来引用 我们知道要引用一个常量,必须用const,所以我再加上const: int const&x=f(); 这样就OK,这不是反过来证明按值返回一个内置类型,返回的是个值,而不是变量它自身吗,如果你想要返回变量自身,那你就要按引用来返回它。
回复 点赞
李刚弄死他 2014年01月26日
引用 29 楼 supermegaboy 的回复:
[quote=引用 28 楼 ALNG 的回复:] 那你解释一下


int I()
{
    return 5;
}

struct S{};
S _S()
{
    return S();
}

int main()
{
     I()=3;  // a compiler error WRT lvalue
     _S()=S(); // this line compile fine
}
都是临时变量,为什么内建类型的不可以被赋值而自定义类型的就可以?
你想多了,其实原因非常简单,甚至与左右值无关,你们只不过被=的抽象形式及其使用习惯给迷惑了。 真正原因是:赋值运算符重载是成员函数,当你写S()=X的时候,它其实是S().operator=( X ),而成员函数是允许在右值上调用的。打完收工,就这么简单。 当然,这会产生一些问题,例如,由于赋值运算符重载通常按照内置赋值运算符的要求返回一个左值,会让如下代码成为合法: S &s = ( S() = S() ); 众所周知,当上述语句结束后,s所绑定的对象无法保证继续存在。 针对类似问题,C++11增加了引用限定符(ref-qualifier)去解决,例如在C++11中,可以如下声明赋值运算符重载: S& operator=( const S & ) &; //ref-qualifier S operator=( const S & ) &&; //ref-qualifier 当*this是右值时,返回一个右值。[/quote] 你这个说法不细致,正确的说法是:当按值返回一个内置类型时,它返回的是一个值,而不是变量,值是常量,比如说1、2、3这样的值,你怎么修改它?你将2赋给2,这可行吗?所以说错误。 但是当按值返回一个对象时,就不同了,因为对象的值就是对象,它不可能是个常量,要按值返回一个对象,那肯定是要调用复制构造函数的,复制完成后的对象怎么可能是个常量呢,除非你修改返回类型,所以不会报错。
回复 点赞
飞天御剑流 2014年01月26日
引用 28 楼 ALNG 的回复:
那你解释一下


int I()
{
    return 5;
}

struct S{};
S _S()
{
    return S();
}

int main()
{
     I()=3;  // a compiler error WRT lvalue
     _S()=S(); // this line compile fine
}
都是临时变量,为什么内建类型的不可以被赋值而自定义类型的就可以?
你想多了,其实原因非常简单,甚至与左右值无关,你们只不过被=的抽象形式及其使用习惯给迷惑了。 真正原因是:赋值运算符重载是成员函数,当你写S()=X的时候,它其实是S().operator=( X ),而成员函数是允许在右值上调用的。打完收工,就这么简单。 当然,这会产生一些问题,例如,由于赋值运算符重载通常按照内置赋值运算符的要求返回一个左值,会让如下代码成为合法: S &s = ( S() = S() ); 众所周知,当上述语句结束后,s所绑定的对象无法保证继续存在。 针对类似问题,C++11增加了引用限定符(ref-qualifier)去解决,例如在C++11中,可以如下声明赋值运算符重载: S& operator=( const S & ) &; //ref-qualifier S operator=( const S & ) &&; //ref-qualifier 当*this是右值时,返回一个右值。
回复 点赞
李刚弄死他 2014年01月26日
引用 56 楼 mujiok2003 的回复:
[quote=引用 24 楼 u011774561 的回复:] 内置类型也有=运算符啊,并且可以轻松地进行赋值操作啊,没有什么问题啊,为什么不可以将一个值赋给一个临时的变量呢,而赋给一个非临时变量就可以呢?
引用
An rvalue should not be confused with the constness of an object. An rvalue does not mean the object would be immutable. There is some confusion about this, since non-class rvalues are non-modifiable. This is not the case with user types. A class rvalue can be used to modify an object through its member functions. Albeit in practice, it can be said that objects are modified only through modifiable lvalues. A modifiable lvalue is an lvalue that can be used to modify the object. Other lvalues are non-modifiable lvalues, const reference is a good example of this. As mentioned already, non-class rvalues do not have the same qualities as the user type rvalues. One might wonder about this. After all, C++ was designed so that user types would behave like built-ins, at least as uniformly as possible. Still this inconsistency exists and the reasons for it shall be explored later. Non-class rvalues are not modifiable, nor can have cv-qualified types (the cv-qualifications are ignored). On the contrary, the class rvalues are modifiable and can be used to modify an object via its member functions. They can also have cv-qualified types. In case of built-ins, some operators require an lvalue as does every assignment expression as the left side. The built-in address-of operator requires an lvalue which reflects the character of lvalues rather well.
具体看看这篇文章.[/quote] 这个文章就是把简单问题复杂化,其实就是一个内置类型的值与类类型的值的问题,你看他洋洋洒洒说了一大片,还是没个中心思想,问题的实质一点也没有说,都是泛泛而谈,真看不起这样的人。
回复 点赞
发动态
发帖子
C++ 语言
创建于2007-09-28

3.1w+

社区成员

24.8w+

社区内容

C++ 语言相关问题讨论,技术干货分享
社区公告
暂无公告