1

ポインターのベクトルと、C++ に付属するイテレーターを使用しています。私が最初に書いた方法では seg fnault が発生しますが、一見些細な変更で、未使用の変数を宣言して初期化すると、seg fault がなくなります。誰かが理由を知っていますか?

障害をセグメント化するコードは次のとおりです。正常に実行される最後の行は 8 行目 (printf ステートメントで検出) であり、4 行目のコメントを外して segfault を取り除きます。

1 Intersect RayTracer::closestShape(Ray r){
2    vector<Shape *>::iterator itStart = scene.getShapes().begin();
3    vector<Shape *>::iterator itEnd = scene.getShapes().end();
4    //vector<Shape *> sceneShapes = scene.getShapes();  This is the unused line that will cause the code to run successfully if I uncomment it.
5    Intersect closest = Intersect();
6    for(;itStart != itEnd; itStart++){
7       Intersect currentIntersect = (*itStart)->intersect(r);
8      if(currentIntersect.isHit()){
9          if(currentIntersect.getT() < closest.getT()){
10              closest = currentIntersect;
            }
        }
     }
     return closest;
}

そして、これがもはやセグメンテーション違反ではない作業バージョンです:

1 Intersect RayTracer::closestShape(Ray r){
2    vector<Shape *> sceneShapes = scene.getShapes();
3    vector<Shape *>::iterator itStart = sceneShapes.begin();
4    vector<Shape *>::iterator itEnd = sceneShapes.end();
5    Intersect closest = Intersect();
6    for(;itStart != itEnd; itStart++){
7       Intersect currentIntersect = (*itStart)->intersect(r);
8      if(currentIntersect.isHit()){
9          if(currentIntersect.getT() < closest.getT()){
10              closest = currentIntersect;
            }
        }
     }
     return closest;
}

誰かがなぜこれが起こっているのかを明確にすることができれば、それは大歓迎です! 問題を明確にするために追加できるものがあれば教えてください。

4

3 に答える 3

7

vector<Shape *> sceneShapes = scene.getShapes();スタック上に永続オブジェクトを作成します。 itStart有効なメモリをitEnd指します。最初の例では、イテレータは無効なメモリを指してscene.getShapes()います。これは、すぐに破棄されてイテレータを無効にした呼び出しからの一時オブジェクトを指しているためです。

行のコメントを外す//vector<Shape *> sceneShapes = scene.getShapes();と、一時的なものと同じメモリ境界に足であるベクトルが返され、イテレータが再び有効になります! しかし、同じになる可能性は 100% ではなく、そのような問題を避けるために細心の注意を払う必要があります。

于 2012-11-16T09:42:07.380 に答える
0

クラッシュの原因はすでに回答されているので、あなたが言及した行のコメントを外すとクラッシュが解消される可能性がある理由を回答してみましょう。関数から返される一時的な名前のないベクトルは、スタックに格納されます。スタックには、ヒープ上のバッキング ストア (この場合は Shape オブジェクトへのポインターである要素の場合) へのポインターが含まれ、サイズや終了について言及する他の人はおそらくほとんどいません。等

イテレータがバッキング ストア (開始と終了) を指している場合に問題が発生します。これは、一時的なベクトルがステートメントの最後 (実際には 2 回) で破棄され、それと共にメモリのバッキング ストア (これはShape オブジェクトへのポインターを含む) がヒープ マネージャーに返されます。名前付きベクター オブジェクトがスタック上に作成されると (コメント アウトされた行のコメントを解除すると)、ベクター コードはおそらく、ヒープ マネージャーから同じメモリ ブロック (名前のないベクターが取得したもの) を取得し、そこで反復子 (ポインター) が有効であるため、クラッシュを回避できます。名前付きベクターが存在しない場合、ヒープ マネージャーはブロックをバラバラにするか、大きなブロックと組み合わせて、後で呼び出した可能性のある他の呼び出し元に割り当ててしまう可能性があります。

于 2012-11-16T10:20:05.287 に答える
0

この機能:

scene.getShapes()

はおそらく値で返されます。つまり、最初の例で呼び出すbegin()end()、バインドされていない一時的にこれらを呼び出すことになります。

参照によって返されるように関数を変更できない場合は、const 参照をバインドしてから、const 参照に対してbegin()andend()を呼び出すことができます (修正された適切なコピーを作成するだけでなく)。

関数を参照で返すように変更できる場合は、そのほうがよいでしょう。理想的には const 参照です。

注: const 参照を返すということは、ベクターのサイズを変更したり、ベクター内のポインターを変更したりできないことを意味しますが、ポインターが指すものは変更できます。これらは Shape へのポインタです。

于 2012-11-16T10:02:30.147 に答える