2016-04-14 76 views
1

我一直在试验矢量和共享指针,我遇到了以下情况。我无法解释发生了什么。该代码是共享指针矢量getter for循环导致问题

#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 

矢量的第1个要素是出于某种原因向另一个存储位置指示。

与下面的一段代码回路更换解决了这个问题,

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; 
} 

可有人请向我解释了什么问题在第一场景。我还有兴趣知道为什么在第二种情况下解决了问题?

+0

嗯...我得到[Segmentation Fault](http://melpon.org/wandbox/permlink/9QB5KpD35gmIJwTK)。为什么? – MikeCAT

+0

我重新编码,没有分割错误。该程序返回代码0. –

回答

4

问题就在这里:

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

getPath()返回一个临时的向量。你叫它两次,所以你得到两个不同的vector s。 itr指向一个临时向量的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; 
} 

而且这样更容易阅读。

+0

哦,这是有道理的。为什么这个问题仅限于第一个元素? –

+2

@PranavKapoor未定义的行为未定义。它可以做任何事情。 – Barry