非常量对象的向量在基于范围的 for 循环中似乎被视为常量
Vector of non-const objects seems to be treated as constant in range-based for loop
我有一个 std::vector
个对象正在通过在 push_back
调用中取消引用 std::unique_ptr
来填充。但是,当我 运行 通过可变的基于范围的 for 循环时,我对这些对象的修改保留在循环的本地。换句话说,尽管循环中缺少 const
关键字,但这些对象似乎被视为常量。这是演示我所看到的内容的最少代码:
#include <vector>
#include <memory>
#include <iostream>
class Item
{
public:
typedef std::unique_ptr<Item> unique_ptr;
inline static Item::unique_ptr createItem()
{
return std::unique_ptr<Item>(new Item());
}
inline const int getValue() const { return _value; }
inline void setValue(const int val) { _value = val; }
private:
int _value;
};
int main()
{
std::vector<Item> _my_vec;
for (int i = 0; i < 5; i++)
{
Item::unique_ptr item = Item::createItem();
_my_vec.push_back(*item);
}
for (auto item : _my_vec)
{
// modify item (default value was 0)
item.setValue(10);
// Correctly prints 10
std::cout << item.getValue() << std::endl;
}
for (auto item : _my_vec)
{
// Incorrectly prints 0's (default value)
std::cout << item.getValue() << std::endl;
}
}
我怀疑这与 std::unique_ptr
的移动语义有关?但这不太有意义,因为即使 push_back
正在调用复制构造函数或其他东西并复制添加的项目而不是指向它,迭代器仍然传递相同的副本,不是吗?
有趣的是,在我的实际代码中,Item
表示的 class 有一个成员变量,它是 vector
指向另一个 [=28= 的对象的共享指针],并且对那些共享指针指向的对象的修改在循环之间持续存在。这就是为什么我怀疑 unique_ptr
.
有什么奇怪的原因
任何人都可以解释这种行为并解释我如何在仍然使用指针的同时解决这个问题吗?
当你像这样编写基于范围的 for 循环时:
std::vector<int> v = ...;
for(auto elt : v) {
...
}
v
的元素被复制到elt
。
在您的示例中,在每次迭代中,您修改 Item
的本地副本而不是向量中的 Item
。
要解决您的问题,请参考:
for (auto& item : _my_vec)
{
item.setValue(10);
std::cout << item.getValue() << std::endl;
}
Vector of non-const objects seems to be treated as constant
如果它被视为常量,那么编译器会冲你大喊大叫,因为写入常量会被视为格式错误,并且编译器会被要求大喊大叫你。显示的代码编译得很好,没有警告。
我怀疑您可能指的是您没有修改向量中的元素这一事实。那是因为你修改了auto item
。该项目不是向量的元素,它是向量中项目的副本。您可以通过使用引用 refer 到该向量中的项目:auto& item
。然后对 item
的修改将是对向量的引用元素的修改。
我有一个 std::vector
个对象正在通过在 push_back
调用中取消引用 std::unique_ptr
来填充。但是,当我 运行 通过可变的基于范围的 for 循环时,我对这些对象的修改保留在循环的本地。换句话说,尽管循环中缺少 const
关键字,但这些对象似乎被视为常量。这是演示我所看到的内容的最少代码:
#include <vector>
#include <memory>
#include <iostream>
class Item
{
public:
typedef std::unique_ptr<Item> unique_ptr;
inline static Item::unique_ptr createItem()
{
return std::unique_ptr<Item>(new Item());
}
inline const int getValue() const { return _value; }
inline void setValue(const int val) { _value = val; }
private:
int _value;
};
int main()
{
std::vector<Item> _my_vec;
for (int i = 0; i < 5; i++)
{
Item::unique_ptr item = Item::createItem();
_my_vec.push_back(*item);
}
for (auto item : _my_vec)
{
// modify item (default value was 0)
item.setValue(10);
// Correctly prints 10
std::cout << item.getValue() << std::endl;
}
for (auto item : _my_vec)
{
// Incorrectly prints 0's (default value)
std::cout << item.getValue() << std::endl;
}
}
我怀疑这与 std::unique_ptr
的移动语义有关?但这不太有意义,因为即使 push_back
正在调用复制构造函数或其他东西并复制添加的项目而不是指向它,迭代器仍然传递相同的副本,不是吗?
有趣的是,在我的实际代码中,Item
表示的 class 有一个成员变量,它是 vector
指向另一个 [=28= 的对象的共享指针],并且对那些共享指针指向的对象的修改在循环之间持续存在。这就是为什么我怀疑 unique_ptr
.
任何人都可以解释这种行为并解释我如何在仍然使用指针的同时解决这个问题吗?
当你像这样编写基于范围的 for 循环时:
std::vector<int> v = ...;
for(auto elt : v) {
...
}
v
的元素被复制到elt
。
在您的示例中,在每次迭代中,您修改 Item
的本地副本而不是向量中的 Item
。
要解决您的问题,请参考:
for (auto& item : _my_vec)
{
item.setValue(10);
std::cout << item.getValue() << std::endl;
}
Vector of non-const objects seems to be treated as constant
如果它被视为常量,那么编译器会冲你大喊大叫,因为写入常量会被视为格式错误,并且编译器会被要求大喊大叫你。显示的代码编译得很好,没有警告。
我怀疑您可能指的是您没有修改向量中的元素这一事实。那是因为你修改了auto item
。该项目不是向量的元素,它是向量中项目的副本。您可以通过使用引用 refer 到该向量中的项目:auto& item
。然后对 item
的修改将是对向量的引用元素的修改。