GCC可能存在错误,foreach循环对阴影进行操作,而不是实际对象

时间:2015-11-01 15:44:27

标签: c++ gcc

我相信我偶然发现了GCC 4.82中的一个错误

考虑以下MCVE:

class foreachtestobject
{
    std::string somevalue;

public:
    foreachtestobject(int i)
    {
        somevalue = "default value "+to_string(i);
    }

    void reSetSomeValue(string newvalue)
    {
        somevalue = newvalue;
    }

    string getValue()
    {
        return somevalue;
    }
};

int main()
{
    vector<foreachtestobject> vec;
    vec.push_back(foreachtestobject(1));
    vec.push_back(foreachtestobject(2));

    //reading via foreach is unproblematic
    for(auto obj : vec )
    {
        cout<<"Object is: "<<obj.getValue()<<endl;
    }

    //changing values inside a foreach
    for (auto obj : vec)
    {
        obj.reSetSomeValue("new name");
    }

    //printing a second time
    for(auto obj : vec )
    {
        cout<<"Object is: "<<obj.getValue()<<endl;
    }//Notice that nothing has changed.

    //now changing via conventional loop
    for (int i = 0; i<vec.size();i++)
    {
        vec[i].reSetSomeValue("this worked");
    }

    //Printing a third time
    for(auto obj : vec )
    {
        cout<<"Object is: "<<obj.getValue()<<endl;
    }//Notice how the values have been changed correctly.
}

通过QTs调试器运行代码,似乎foreach循环创建了对象的临时副本,内存地址与两个实际对象中的任何一个都不匹配。因此,当调用reSetSomeValue时,将调用阴影对象上的函数。

我可能会补充一点,我并不完全确定QT实际上是用gcc 4.8.2编译的。我碰巧知道我不久前更新了GCC,我不知道QT是否会自动使用更新版本。命令GCC --version报告4.8.2。

这让我觉得很奇怪,更不用说低效了,如果复制了每个迭代的对象,它代表了相当大的开销。根据我发现的任何来源,foreach循环应该像传统循环一样工作,但在这里它不会。

如果说的话,这是一个错误吗?如果没有,为什么?

2 个答案:

答案 0 :(得分:4)

for(auto obj : vec )

确实并且应该在语言规则中创建范围元素的副本。如果你想要一个参考,请说:

for(auto &obj : vec )

答案 1 :(得分:2)

  

似乎foreach循环创建了对象的临时副本

您是不是认为这是因为这是您编写的代码?这里唯一的“错误”是你:你正在操作数组元素的副本。

如果您希望使用原始版本,请使用references。例如:

for (auto& el : container)
//       ^

当你遇到问题时,指责编译器是错误的是最后的手段,而不是第一个(除非你使用的是Visual Studio)。至少查看ranged-for循环结构意味着什么。