共享指针矢量getter for for循环导致问题

时间:2016-04-14 13:38:30

标签: c++ vector shared-ptr

我一直在尝试使用向量和共享指针,我遇到了以下情况。我无法解释发生的事情。代码是

#include<iostream>
#include<vector>
#include<memory>

class A
{
    public:
    int val;
    A(int val1): val(val1){}
};

class B
{
    std::vector< std::shared_ptr<A> > path;

    public:

    std::vector< std::shared_ptr<A> > getPath() { return path; }

    void doIt()
    {
        std::shared_ptr<A> a1 = std::make_shared<A>(1);
        std::shared_ptr<A> a2 = std::make_shared<A>(2);
        std::shared_ptr<A> a3 = std::make_shared<A>(3);
        path.push_back(a1);
        path.push_back(a2);
        path.push_back(a3);

        std::cout<<"In function"<<std::endl;
        for(std::vector< std::shared_ptr<A> >::iterator itr = path.begin(),
            endItr = path.end(); itr != endItr; ++itr)
        {
            std::cout<<&(*(*itr))<<": "<<(*itr)->val<<std::endl;
        }
    }
};

int main()
{
    B b;
    b.doIt();
    std::cout<<"In main"<<std::endl;
    for(std::vector< std::shared_ptr<A> >::iterator itr = b.getPath().begin(),
    endItr = b.getPath().end(); itr != endItr; ++itr)
    {
        std::cout<<&(*(*itr))<<": "<<(*itr)->val<<std::endl;
    }
}

我得到的输出是

In function
0x30dc8: 1
0x31780: 2
0x317a0: 3
In main
0x35f18: 196800
0x31780: 2
0x317a0: 3

向量的第一个元素由于某种原因指向另一个内存位置。

使用以下代码替换for循环可以解决问题,

std::vector< std::shared_ptr<A> > path = b.getPath();
for(std::vector< std::shared_ptr<A> >::iterator itr = path.begin(),
    endItr = path.end(); itr != endItr; ++itr)
{
    std::cout<<&(*(*itr))<<": "<<(*itr)->val<<std::endl;
}

有人可以向我解释第一种情况出了什么问题。我还想知道为什么问题在第二种情况下得到了解决?

1 个答案:

答案 0 :(得分:4)

问题在于:

for(std::vector< std::shared_ptr<A> >::iterator itr = b.getPath().begin(),
    endItr = b.getPath().end(); itr != endItr; ++itr)

getPath()返回一个临时向量。你正在调用它两次,所以你得到两个不同的 vectoritr指向一个临时向量的begin()endItr指向不同临时向量的末尾。在输入for循环之前,两个临时向量都超出了范围,所以一旦取消引用,就会访问已经删除的内存。

这样做:

std::vector< std::shared_ptr<A> > path = b.getPath();

解决了这个问题,因为现在两个迭代器都指向相同的向量,这也将比两个迭代器都长。

另外,C ++ 11。如果您只使用基于范围的表达式,则不会出现此问题:

for (auto& a : b.getPath())
{
    std::cout << &*a << ": " << a->val << std::endl;
}

这更容易阅读。