1

このコードを見てください:

#include <vector>
#include <iostream>
#include <string>
using namespace std;

class A
{
    private:
        string contentA;

    public:
        A(){ contentA = ""; };
        A( string setContent ){ contentA = setContent; };
        virtual string printContent(){ return contentA; };
};

class B: public A
{
    private:
        string contentB;

    public:
        B( string setContent ){ contentB = setContent; };
        virtual string printContent(){ return contentB; };
};

int main()
{

    vector<A*> aPointer;
    vector<B> bVector;      

    B b1("b1");
    //store b1 obj in bVector
    bVector.push_back( b1 );
    //store the current(last) obj address to aPointer for access later
    aPointer.push_back( &bVector.back() );

//    B b2("b2");
//    bVector.push_back( b2 );
//    aPointer.push_back( &bVector.back() );

    for( vector<A*>::iterator it = aPointer.begin(); it != aPointer.end(); it++ )
    {
        cout << (*it)->printContent() << endl;
    }
}

aPointer は、B ベクトルの要素へのポインターを格納します。

for ループで B ベクトルの 2 番目の要素にアクセスすると、セグメンテーション違反が発生するのはなぜですか?

私は六角形を入れました、そしてそれは再びうまくいきます。

4

3 に答える 3

2

問題は、 の 2 番目の要素にアクセスするときではなくaPointer、最初の要素にアクセスするときです。ご覧のとおり、この問題は、std::vectorメモリの拡張/サイズ変更および再割り当て時に発生します。これを行うと、参照 (ポインター、反復子、および&参照) が無効になります。つまり、無効化された参照にアクセスすると、未定義の動作が発生します (この場合の効果は、セグメンテーション違反です)。

問題の真の原因を見てみましょう。

B b1("b1");
bVector.push_back( b1 );
aPointer.push_back( &bVector.back() );

B b2("b2");
bVector.push_back( b2 );
aPointer.push_back( &bVector.back() );

うおお!追加時にアドレスが保存されている 2 つの要素をプッシュ バックしています。問題はそこにあります。2 番目push_backの を実行すると、再割り当てとサイズ変更が発生するため、 内の既存の要素への参照が無効になりますbVector。そして、そのベクトル内に既存の要素があり、それへの参照がすでに無効になっています! その参照は現在 の最初の要素でaPointerあり、指してアクセスすることを想定していないメモリ位置を指しています。

したがって、反復を実行すると、 の最初の要素にアクセスするaPointerため、セグメンテーション違反が発生します。

あなたの問題を解決するには、別のベクトルの対応する要素へのポインタのベクトルを保存しないでください! ベクトル全体を渡して (できれば参照によって、コピーのコストが発生しないようにすることをお勧めします)、要素自体に対して直接操作を行うことができます。これにより、頭痛の種が確実に 1 時間短縮され、より優れた短いコードが作成されます。

于 2013-10-24T08:03:04.030 に答える
1

Joachim Pileborg と Mark Garcia の両方が言及しているように、これはベクトル コンテナーがメモリを再割り当てする際の問題です。

これを解決するには、vector.reserveメソッドを使用してベクターにメモリを事前に割り当てることができます。これはここでの状況ではうまくいきますが、これは単なる応急処置であり、これを修正する方法と見なすべきではありません. 編集: 興味があるかもしれないという理由だけでこれを投稿したことを強調したいと思います. Joachim と Mark は、根本的な問題に対処するための適切な方法を提供します。

int main()
{

    vector<A*> aPointer;
    vector<B> bVector;      

    //reserve some space. There's no special meaning to choosing 16.
    aPointer.reserve(16);
    bVector.reserve(16); 

    B b1("b1");
    bVector.push_back( b1 );
    aPointer.push_back( &bVector.back() );

    B b2("b2");
    bVector.push_back( b2 );
    aPointer.push_back( &bVector.back() );

    for( vector<A*>::iterator it = aPointer.begin(); it != aPointer.end(); it++ )
    {
        cout << (*it)->printContent() << endl;
    }
}
于 2013-10-24T08:14:12.183 に答える