2016-04-14 14 views
1

ベクタと共有ポインタを試してみたところ、次のようなシナリオが発生しました。私は何が起こっているのか説明することは紛失している。コードは、私が手出力が問題の原因となるforループの共有ポインタベクタgetter

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

ベクトルの第一要素が別のメモリ位置に向いているいくつかの理由である

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

です。以下のコードでループのための交換

は、問題を解決し、

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

は、誰かが第一のシナリオで何が悪かったのか私に説明していただけます。私はさらに、問題が2番目のケースで解決された理由を知ることに興味がありますか?

+0

Hmmm ... [セグメンテーションフォルト](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()。 2回呼び出すと、と2つの異なるvectorが返されます。 itrは、1つのテンポラリベクトルの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

関連する問題