C++ '=';:左操作数必须是l值

C++ '=';:左操作数必须是l值,c++,C++,编译以下代码时,我在“m.msg_body[I].id=I;”处得到了“error C2106:'=':左操作数必须是l值”。当我注释掉那一行时,没有错误。我的代码有什么问题 static const short MSG_DATA_MAX = 10; struct MsgBodyData { int id; string value; }; class MsgBody { public: MsgBody() { len = 0;

编译以下代码时,我在“m.msg_body[I].id=I;”处得到了“error C2106:'=':左操作数必须是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";
    }
}
static const short MSG\u DATA\u MAX=10;
结构MsgBodyData
{
int-id;
字符串值;
};
类MsgBody
{
公众:
MsgBody()
{
len=0;
}
MsgBody(MsgBody&msg_obj);
~MsgBody(){}
int length(){return len;}
void setLength(int_len){len=_len;}
MsgBodyData运算符[](短索引)
{
如果(索引>-1&&index
您的
操作符[]
返回一个临时值(右值),使其每个成员都成为右值。语言禁止赋值给右值(确切地说,是赋值给非类类型的右值),这就是错误告诉您的

这种限制的原因是,由于左手边将在完全表达结束时被破坏,因此赋值没有多大意义(它将随着临时破坏而被遗忘)


如果要修改类中保存的元素,则需要返回对存储元素的引用(左值),而不是副本。

您的
运算符[]
按值返回,这意味着它将生成一个临时副本并返回该副本。临时值是右值。您应该修改运算符以返回引用。实际上,您应该有两个版本,一个是常量版本,返回常量引用,另一个是非常量版本,返回非常量引用


不过,您处理超出范围索引的方法必须更改。您可以抛出一个异常,或者干脆将其作为未定义的行为保留,只要确保记录它即可。另一个选择是在类中有一个伪
MsgBodyData
对象,当你得到一个坏的索引时返回该对象,但这似乎是一个非常愚蠢的设计。

在抛出异常后,我是否可以为超出范围的索引返回NULL?如果你抛出异常,您没有返回任何内容。@LwinHtooKo:您的
MsgBodyData
如何转换为NULL?即使可以,这仍然是一个右值。在抛出异常之后?这没有意义,因为永远不会到达return语句。@LwinHtooKo:因为
value
的类型是
std::string
。类,而不是内置的。可以(尽管不推荐)为类编写赋值运算符,该类除了赋值给对象之外还有一些副作用。在这种情况下,对右值的赋值可能有意义。我想标准委员会不是要求编译器分析赋值运算符是否有这样的副作用,而是决定全面允许它。(这只是猜测,我不知道标准委员会的推理是什么)