2012-08-08 168 views
2

当我编译下面的代码时,我得到了“error C2106:'=':左操作数必须是l值”at“m.msg_body [i] .id =一世;”。当我评论这一行时,没有错误。我的代码有什么问题?'=':左操作数必须是l值

static const short MSG_DATA_MAX = 10; 

struct MsgBodyData 
{ 
    int id; 
    string value; 
}; 

class MsgBody 
{ 
public: 
    MsgBody() 
    { 
     len = 0;  
    } 
    MsgBody(MsgBody & msg_obj); 
    ~MsgBody() {} 

    int length() { return len; } 
    void setLength(int _len) { len = _len; } 

    MsgBodyData operator[](short index) 
    { 
     if(index > -1 && index < MSG_DATA_MAX) 
      return data[index]; 

     MsgBodyData dump_data; 
     return dump_data; 
    } 

    void operator=(MsgBody & msg_obj) 
    { 
     len = msg_obj.length(); 
     for(int i = 0; i < len; ++i) 
      data[i] = msg_obj[i]; 
    } 

private: 
    int len; 
    MsgBodyData data[MSG_DATA_MAX]; 
}; 

MsgBody::MsgBody(MsgBody &msg_obj) 
{ 
    operator=(msg_obj); 
} 

struct Msg 
{ 
    int msg_id; 
    string msg_title; 
    MsgBody msg_body; 
}; 


void sendMsg() 
{ 
    Msg m; 
    m.msg_id = 1; 
    m.msg_title = "test_msg"; 

    int size = MSG_DATA_MAX; 

    for(int i = 0; i < size; ++i) 
    { 
     m.msg_body[i].id = i; // HERE I GOT ERROR !!! 
     m.msg_body[i].value = "test_value"; 
    } 
} 

回答

5

您的operator[]按值返回,这意味着它会进行临时复制并返回该值。临时工是rvalues。您应该修改您的操作员以返回参考。实际上,你应该有两个版本,一个是const版本,它返回一个const引用,另一个是非const版本,它返回一个非const引用。

你的处理超范围索引的方法将不得不改变。你可以抛出一个异常,或者将它作为未定义的行为,只要确保记录它。另一个选择是在类中有一个虚拟的MsgBodyData对象,当你得到一个糟糕的索引时,你会返回这个对象,但这看起来像一个非常愚蠢的设计。

+0

抛出异常后,我可以只为索引超出范围返回NULL吗? – 2012-08-08 04:32:06

+1

如果抛出异常,则不返回任何内容。 – Puppy 2012-08-08 04:34:30

+0

@LwinHtooKo:你的MsgBodyData如何转换为NULL?即使可能,这仍然是一个右值。 *抛出异常之后?没有意义,因为回报声明永远不会达成。 – 2012-08-08 04:35:50

3

operator[]返回临时(右值),这使得其成员的右值中的每一个。语言禁止赋值给右值(准确地说,赋值给非类类型的右值),这就是错误告诉你的。

该限制的原因是,由于左手边将在完整表达式的末尾被销毁,所以分配没有多大意义(它会被暂时的破坏所遗忘)。

如果您打算修改类内部的元素,则需要将引用(左值)返回给存储的元素,而不是副本。