我相信我偶然发现了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循环应该像传统循环一样工作,但在这里它不会。
如果说的话,这是一个错误吗?如果没有,为什么?
答案 0 :(得分:4)
for(auto obj : vec )
确实并且应该在语言规则中创建范围元素的副本。如果你想要一个参考,请说:
for(auto &obj : vec )
答案 1 :(得分:2)
似乎foreach循环创建了对象的临时副本
您是不是认为这是因为这是您编写的代码?这里唯一的“错误”是你:你正在操作数组元素的副本。
如果您希望使用原始版本,请使用references。例如:
for (auto& el : container)
// ^
当你遇到问题时,指责编译器是错误的是最后的手段,而不是第一个(除非你使用的是Visual Studio)。至少查看ranged-for循环结构意味着什么。