2016-04-14 77 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