非const对象的向量似乎在基于范围的for循环

时间:2017-07-21 15:08:37

标签: c++ c++11 pointers smart-pointers unique-ptr

我通过std::vector调用中的std::unique_ptr取消引用来填充push_back个对象。但是,当我运行一个可变的基于范围的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这里表示的类有一个成员变量,它是另一个类的对象的共享指针的vector,以及对指向的对象的修改这些共享指针在循环之间持续存在。这就是为什么我怀疑unique_ptr有一些时髦的东西。

任何人都可以解释这种行为并解释我在使用指针时如何解决这个问题吗?

2 个答案:

答案 0 :(得分:4)

当您编写基于范围的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;
}

答案 1 :(得分:3)

  

非const对象的向量似乎被视为常量

如果被视为常量,那么编译器会尖叫你,因为写入常量被视为格式错误,编译器会被要求尖叫。显示的代码编译得很好,没有任何警告。

我怀疑你可能指的是你没有修改向量中的元素。那是因为你修改了auto item。该项不是向量的元素,它是向量中项的副本。您可以使用引用{em}将引用到该向量中的项目:auto& item。然后对item的修改将是对向量的引用元素的修改。