临时对象, vector(c).swap(c)

John_Cash 2007-01-28 08:45:03
vector的这种swap shrink调用到了临时对象的非const方法, 感觉比较诡异;

简化一下:

struct Foo{
int a;
void change(){a=42;}
};

我用vc7.1试了下:
Foo().change();是允许的;
而:
Foo().a = 42;
却要求 error C2106: '=' : left operand must be l-value

哪位解释下, 或者哪本书里讨论了这个冬冬?
thanks,
...全文
776 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
OOPhaisky 2007-01-29
  • 打赏
  • 举报
回复
右值对象(r-value object)并不等价于常量对象(const object)。
右值对象(或右值表达式)不可以放在等号左边,而常量对象(或常量表达式)既不可以被放在等号左边,也不可以经由它调用非const成员函数。
-------------------------------------------------------------------------------------
up
晨星 2007-01-29
  • 打赏
  • 举报
回复
其实右值对象上调用函数完全可能返回左值,比如:
DatabaseConnection* p = DriverManager().getDatabaseConnection();
晨星 2007-01-29
  • 打赏
  • 举报
回复
右值对象(r-value object)并不等价于常量对象(const object)。
右值对象(或右值表达式)不可以放在等号左边,而常量对象(或常量表达式)既不可以被放在等号左边,也不可以经由它调用非const成员函数。
——差不多所有的就只有这些了。

C++语言并没说右值对象上不能调用任何非const成员函数。
除非那个右值对象同时也是const对象,比如对于函数:
const string get_string();
而言,下面的
get_string().clear();
是错误的。
而如果是:
string get_string();
则没有问题。
晨星 2007-01-29
  • 打赏
  • 举报
回复
我感觉你的问题可能在于觉得右值既然不可以放在等号左边,于是它就是常量。
而实际上“不可以放在等号左边”跟“常量”还不是一个概念。
晨星 2007-01-29
  • 打赏
  • 举报
回复
Foo()不会是常量对象。
因为构造函数无法指定为“const”——它连返回值都没有。

一般函数调用如果返回的不是左值,那么是不是常就看返回的是不是const对象了,比如:
string f();
将返回一个一般的右值对象。
const string f();
将返回一个常量的右值对象。
只有跟“常量”沾上边以后,才不可以调用非const函数。
htqx 2007-01-29
  • 打赏
  • 举报
回复
如果 Foo().change() 可以对应:
void foo_change(Foo* const foo){
foo->a = 42;
}
调用 foo_change(&(Foo())); vc7.1会有warning:
-----------------------------------------------------

我感觉Foo().change()的定义应该是:
void foo_change( Foo & foo );

普通类型就是内置的:
int, short, long之类的简单类型.
复杂的就是class ,struct等通过简单类型构成的复合类型.




sdlyczl 2007-01-29
  • 打赏
  • 举报
回复
普通类型临时变量是不能更改的.
但是复杂类型可以.

哪些是精通类型临时变量,哪些是复杂类型变量,举个例子看看
sdlyczl 2007-01-29
  • 打赏
  • 举报
回复
to:steedhorse(晨星) ( ) 信誉:141 Blog
你说的比较高深啊,能不能再详细点?
比如:Foo()是一个常量对象还是右值对象?

“其实右值对象上调用函数完全可能返回左值,比如:
DatabaseConnection* p = DriverManager().getDatabaseConnection();”联系到lz所说的例子,是指哪一块?
逸学堂 2007-01-29
  • 打赏
  • 举报
回复
void swap(_Myt& _Right)
{ // exchange contents with _Right
if (this->_Alval == _Right._Alval)
{ // same allocator, swap control information
std::swap(_Myfirst, _Right._Myfirst);
std::swap(_Mylast, _Right._Mylast);
std::swap(_Myend, _Right._Myend);
}
else
{ // different allocator, do multiple assigns
_Myt _Ts = *this; *this = _Right, _Right = _Ts;
}
}

这种形式的处理,看编译器的实现,标准上并没有规定
void vv(Foo& abc)
{
abc.a = 42;
}
vv(Foo());
比如对如上形式的处理,并非是一个const类型
taodm 2007-01-29
  • 打赏
  • 举报
回复
htqx(航天奇侠) 所答已经够了,再深入论坛只会越讨论越复杂。
-----------------------------
htqx(航天奇侠) ( ) 信誉:90 Blog 2007-1-28 22:49:25 得分: 0

普通类型临时变量是不能更改的.
但是复杂类型可以.




晨星 2007-01-29
  • 打赏
  • 举报
回复
偶还没说明白么?
你把它放到等号左边去,自然要求它是左值,那是没办法了。
但调用一个非const的成员函数,没有必要必须是左值,右值也可以,只要别是个const右值就行。
John_Cash 2007-01-29
  • 打赏
  • 举报
回复
to blueoceanli(谋定而动) : 这里是在讨论临时变量的问题, 具名变量自然是正确的:
Foo mytest;
mytest.change();
blueoceanli 2007-01-29
  • 打赏
  • 举报
回复
#include <iostream>

struct Foo{
public:
int a;
void change(){a=42;}
};
int main()
{
Foo mytest;
mytest.change();
std::cout << mytest.a<< std::endl;
mytest.a=100;
std::cout << "aaaaaaaaaaaaaaaa" << std::endl;
std::cout << mytest.a<< std::endl;
return 0;
}
blueoceanli 2007-01-29
  • 打赏
  • 举报
回复
把你的结构体搞成这样就可以了.
struct Foo{
public:
int a;
void change(){a=42;}
};
John_Cash 2007-01-29
  • 打赏
  • 举报
回复
如果 Foo().change() 可以对应:
void foo_change(Foo* const foo){
foo->a = 42;
}
调用 foo_change(&(Foo())); vc7.1会有warning:
warning C4238: nonstandard extension used : class rvalue used as lvalue

而Foo().change() 却没问题, 编译器对隐藏的this作了特殊关照?
John_Cash 2007-01-29
  • 打赏
  • 举报
回复
其实overload一下=, Foo::operator = (int) 是可以的.

再深下去意义不大, 结贴了, 谢谢各位.
晨星 2007-01-29
  • 打赏
  • 举报
回复
也可以这样理解吧。
总之从来没见过哪里“规定”说右值不能调用non-const函数,所以也不明白你为啥这么不理解。没有规定说不可以的事,往往就是可以的呀。

至于右值不能放在赋值号左边,这是肯定是有规定的。
John_Cash 2007-01-29
  • 打赏
  • 举报
回复
翻了翻TCPL, 可以这样理解:
Foo().change()之所以被允许是因为change()里可以做non-trivial的事情;
比如: printf((s1+s2).c_str());

而Foo().a = 42; 这种对临时对象的data member赋值的事情没什么意义, 就被禁止了.

所以这里更多的是一个规定而非l/r-value的实现问题.
htqx 2007-01-28
  • 打赏
  • 举报
回复
调用函数和直接修改会相同么?虽然目的相同,但是方法是不同的.
John_Cash 2007-01-28
  • 打赏
  • 举报
回复
我的理解是, 既然Foo().change()和 Foo().a = 42作了相同的事情, 为什么前者可以而后者不可以?
加载更多回复(2)

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧