2009-08-05 12 views
1

C/C++を書いてから数年が経ちましたが、今は自分で解決できないような問題に直面しています。C++変数のデータが上書きされています

struct InputData 
{ 
    float diameter; 
    float length; 
    int vertIndex; 
    struct InputData *parent; 
    vector<InputData*> children; 
    bool deadEnd; 

    InputData(float dia, float lngth) 
    { 
     diameter = dia; 
     length = lngth; 
     vertIndex = NULL; 
     parent = NULL; 
     deadEnd = false; 
    } 
}; 

私は、ノードの数、およびその親/子関係を定義することから始め:唯一のノードがないようI5

InputData i0 = InputData(3.0f, 3.0f); 
InputData i1 = InputData(2.0f, 2.0f); 
InputData i2 = InputData(1.0f, 1.0f); 
InputData i3 = InputData(1.0f, 1.0f); 
InputData i4 = InputData(1.0f, 1.0f); 
InputData i5 = InputData(1.01f, 0.5f); 

i0.children.push_back(&i1); 
i1.children.push_back(&i2); 
i2.children.push_back(&i3); 
i3.children.push_back(&i4); 
i4.children.push_back(&i5); 

i1.parent = &i0; 
i2.parent = &i1; 
i3.parent = &i2; 
i4.parent = &i3; 
i5.parent = &i4; 

注次構造体を考えると

子供がいます。

私は、このデータを使用していくつかの作業を行うために移動する((BuildMeshVerticesを呼び出してから& I0、&頂点を)メイン())、およびi5に子を追加し終わる:

void BuildMeshVertices(InputData* current, vector<SimpleVertex> *vertices) 
{ 
    //Do work 

    if(current->children.size() == 1) 
    { 
     BuildMeshVertices(current->children[0], vertices); 
    } 
    else if(current->children.size() == 0 && current->deadEnd == false) 
    { 
     InputData iDeadEnd = InputData(1.01f, 0.5f); 
     iDeadEnd.deadEnd = true; 
     iDeadEnd.parent = current; 
     current->children.push_back(&iDeadEnd);  

     BuildMeshVertices(&iDeadEnd, vertices); 
    } 
} 

ているすべてのものの後結構です。 i0には1つの子(i1)があり、i1には1つの子(i2)があるため、i5にも子があります。

私は別の関数(BuildMeshIndices())を呼び出し、この関数に数行(63行目)を突然追加して、i5に新しく追加された子のデータを上書きしています。 i5はまだ正しい子を指していますが、この子のデータは突然文字化けしています。

はここにスクリーンショットbefore and afterです(リンクについては申し訳ありませんが、私はIMGタグを使用することを許されなかった)、これがなぜ起こるか

私が把握することはできませんが、私はそれはとは何かを持っている感じを持っています私の貧しい記憶管理?

UPDATEまた、このようにする必要はありません。たとえば、子ベクトルを値のベクトルに変更することがC++の推奨方法であれば、私はそれを好むでしょう。私は答えにコメントしようとしましたが、皆さんがコメントを見ているのかどうかはわかりません(FAQによると、コメントを残すには50の評判が必要です)。以下は

は、(ストリッピング不要ますが、エラーを再現するのに十分なすべてのものを含む)完全なソースコードです:

#include "stdafx.h" 
#include <vector> 

using std::vector; 

struct InputData 
{ 
    float diameter; 
    float length; 
    int vertIndex; 
    struct InputData *parent; 
    vector<InputData*> children; 
    bool deadEnd; 

    InputData(float dia, float lngth) 
    { 
     diameter = dia; 
     length = lngth; 
     vertIndex = NULL; 
     parent = NULL; 
     deadEnd = false; 
    } 
}; 

//-------------------------------------------------------------------------------------- 
// Vertex types 
//-------------------------------------------------------------------------------------- 
struct SimpleVertex 
{ 
    float Pos; 

    SimpleVertex(float Position) 
    { 
     Pos = Position; 
    } 
}; 

void BuildMeshVertices(InputData* current, vector<SimpleVertex> *vertices) 
{ 
    current->vertIndex = vertices->size(); 

    //Add vertices.. 

    if(current->children.size() == 1) 
    { 
     BuildMeshVertices(current->children[0], vertices); 
    } 
    else if(current->children.size() == 0 && current->deadEnd == false) 
    { 
     InputData iDeadEnd = InputData(1.01f, 0.5f); 
     iDeadEnd.deadEnd = true; 
     iDeadEnd.parent = current; 
     current->children.push_back(&iDeadEnd);  

     BuildMeshVertices(&iDeadEnd, vertices); 
    } 
} 

void BuildMeshIndices(InputData* current, vector<unsigned long> *indices) 
{ 
    indices->push_back(current->vertIndex+2); 
    indices->push_back(current->vertIndex+0); 
    indices->push_back(current->vertIndex+1); 
    indices->push_back(current->vertIndex+3); 
    indices->push_back(current->vertIndex+0); 
    indices->push_back(current->vertIndex+2); 

    InputData *parent = current->parent; 

    unsigned long vOffset; 

    if(parent != NULL && parent->children.size() == 1) 
    { 
     vOffset = (unsigned long)current->vertIndex; 

     indices->push_back(vOffset+7); 
     indices->push_back(vOffset+5); 
     indices->push_back(vOffset+4); 
     indices->push_back(vOffset+6); 
     indices->push_back(vOffset+5); 
     indices->push_back(vOffset+7); 

     indices->push_back(vOffset+10); 
     indices->push_back(vOffset+8); 
     indices->push_back(vOffset+9); 
     indices->push_back(vOffset+11); 
     indices->push_back(vOffset+8); 
     indices->push_back(vOffset+10); 

     indices->push_back(vOffset+15); 
     indices->push_back(vOffset+13); 
     indices->push_back(vOffset+12); 
     indices->push_back(vOffset+14); 
     indices->push_back(vOffset+13); 
     indices->push_back(vOffset+15); 

     indices->push_back(vOffset+18); 
     indices->push_back(vOffset+16); 
     indices->push_back(vOffset+17); 
     indices->push_back(vOffset+19); 
     indices->push_back(vOffset+16); 
     indices->push_back(vOffset+18); 
    } 

    if(current->children.size() == 1 && current->deadEnd == false) 
    { 
     BuildMeshIndices(current->children[0], indices); 
    } 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    InputData i0 = InputData(3.0f, 3.0f); 
    InputData i1 = InputData(2.0f, 2.0f); 
    InputData i2 = InputData(1.0f, 1.0f); 
    InputData i3 = InputData(1.0f, 1.0f); 
    InputData i4 = InputData(1.0f, 1.0f); 
    InputData i5 = InputData(1.01f, 0.5f); 

    i0.children.push_back(&i1); 
    i1.children.push_back(&i2); 
    i2.children.push_back(&i3); 
    i3.children.push_back(&i4); 
    i4.children.push_back(&i5); 

    i1.parent = &i0; 
    i2.parent = &i1; 
    i3.parent = &i2; 
    i4.parent = &i3; 
    i5.parent = &i4; 

    // Create vertex buffer 
    vector<SimpleVertex> vertices; 

    BuildMeshVertices(&i0, &vertices); 

    // Create index buffer 
    vector<unsigned long> indices; 

    BuildMeshIndices(&i0, &indices); 

    return 0; 
} 

答えて

1

生ポインタをsmart pointersに変更すると、メモリ管理上の問題が発生します。

すべてのブーストをプロジェクトにコピーする必要はなく、必要なヘッダーだけをコピーしてください。

#include <vector> 
#include <boost/shared_ptr.hpp> 
#include <boost/weak_ptr.hpp> 

struct InputData 
{ 
    float diameter; 
    float length; 
    unsigned long vertIndex; 
    boost::weak_ptr<InputData> parent; 
    std::vector< boost::shared_ptr<InputData> > children; 
    bool deadEnd; 

    InputData(float dia, float lngth, boost::weak_ptr<InputData> p = boost::weak_ptr<InputData>(), bool de = false) 
     : diameter(dia), length(lngth), vertIndex(0), parent(p), deadEnd(de) {} 
}; 

struct SimpleVertex 
{ 
    float Pos; 

    SimpleVertex(float position) : Pos(position) {} 
}; 

void BuildMeshVertices(boost::shared_ptr<InputData> current, std::vector<SimpleVertex>& vertices) 
{ 
    current->vertIndex = vertices.size(); 

    //Add vertices.. 
    if(current->children.size() == 1) 
    { 
     BuildMeshVertices(current->children[0], vertices); 
    } 
    else if(current->children.size() == 0 && current->deadEnd == false) 
    { 
      // this was a stack variable, so the pointer became invalid when going out of ambit. 
     boost::shared_ptr<InputData> iDeadEnd(new InputData(1.01f, 0.5f, current, true)); 
     current->children.push_back(iDeadEnd);   

     BuildMeshVertices(iDeadEnd, vertices); 
    } 
} 

void BuildMeshIndices(boost::shared_ptr<InputData> current, std::vector<unsigned long>& indices) 
{ 
    unsigned long vi = current->vertIndex; 
    unsigned long ioffset[] = { vi+2, vi, vi+1, vi+3, vi, vi+2}; 
    indices.insert(indices.end(), ioffset, ioffset+6); 

    boost::shared_ptr<InputData> parent = current->parent.lock(); 
    if (parent && parent->children.size() == 1) 
    { 
     unsigned long offs = current->vertIndex; 
      unsigned long voffset[] = 
      { offs+7, offs+5, offs+4, offs+6, offs+5, offs+7, 
      offs+10, offs+8, offs+9, offs+11, offs+8, offs+10, 
      offs+15, offs+13, offs+12, offs+14, offs+13, offs+15, 
      offs+18, offs+16, offs+17, offs+19, offs+16, offs+18 }; 
      indices.insert(indices.end(), voffset, voffset+24); 
    } 

    if(current->children.size() == 1 && current->deadEnd == false) 
    { 
     BuildMeshIndices(current->children[0], indices); 
    } 
} 

int main() 
{ 
    boost::shared_ptr<InputData> i0(new InputData(3.0f, 3.0f)); 
    boost::shared_ptr<InputData> i1(new InputData(2.0f, 2.0f)); 
    boost::shared_ptr<InputData> i2(new InputData(1.0f, 1.0f)); 
    boost::shared_ptr<InputData> i3(new InputData(1.0f, 1.0f)); 
    boost::shared_ptr<InputData> i4(new InputData(1.0f, 1.0f)); 
    boost::shared_ptr<InputData> i5(new InputData(1.01f, 0.5f)); 

    i0->children.push_back(i1); 
    i1->children.push_back(i2); 
    i2->children.push_back(i3); 
    i3->children.push_back(i4); 
    i4->children.push_back(i5); 

    i1->parent = i0; 
    i2->parent = i1; 
    i3->parent = i2; 
    i4->parent = i3; 
    i5->parent = i4; 

    // Create vertex buffer 
    std::vector<SimpleVertex> vertices; 
    BuildMeshVertices(i0, vertices); 

    // Create index buffer 
    std::vector<unsigned long> indices; 
    BuildMeshIndices(i0, indices); 

    return 0; 
} 

まだ半分のC、半分のC++の汚れたコードがあると思います...あなたは言語を選択する必要があります。

+0

すごい!私はブーストライブラリを認識していませんでしたが、私はそれを知る必要があるように見えます。 – Tchami

+0

共有ポインタ/弱ポインタ​​がC++ 03標準に追加されました。コンパイラの中には、tr1/memoryヘッダのstd :: tr1名前空間や、メモリヘッダのstd namespaceのC++ 0xをサポートしているコンパイラで実装されているものがあります。 –

7

あなたのベクトルにスタックオブジェクトへのポインタを推進しています。一旦実行されると、オブジェクトをスタックするスコープが破棄され、メモリが再利用され、偽の値になります。試してみてください。

InputData *iDeadEnd = new InputData(1.01f, 0.5f); 
iDeadEnd->deadEnd = true; 
iDeadEnd->parent = current; 
current->children.push_back(iDeadEnd); 

その後、適切な時期にそのメモリを解放する必要があります。

+0

ありがとうございました。それはトリックをするようですが、メモリを解放する方が好ましいでしょうか?いつ? – Tchami

+0

boost :: shared_ptrまたはboost :: ptr_vectorを使用することができます。 – bdonlan

+0

ツリーを歩いて手動でメモリを解放する必要があります。それは特に難しいことではありませんが、1つのステップを逃したときにメモリリークが発生します。 –

1

ポインターを操作するには、ダイナミックメモリを使用する必要があります。 の入力データは、BuildMeshVerticesから外に出ると破棄されるため、データがガベージされるか、メモリ例外が発生します。

あなたは

InputData * iDeadEnd = new InputData(1.01f, 0.5f); 

代わりの

InputData iDeadEnd = InputData(1.01f, 0.5f); 
0

あなたBuildMeshVertices機能を使用すると、スタック上にそれを宣言しているためiDeadEnd(I5の子)が解体された後、終了した瞬間のようにして出て行くことによって何かをする必要がありますスタックフレーム全体が無効になり、すべてのオブジェクトが分解されます。動的にiDeadEndを割り当てたり、ツリーをどのように定義するかを根本的に再考したりすることができます。でも、それは明白な理由のための理想からほど遠い

InputData i0 = InputData(3.0f, 3.0f); 
i0.children.push_back(InputData(2.0f, 2.0f)); 
i0.children[0].children.push_back(InputData(1.0f, 1.0f)); 

など

を:あなたは、それらを次のように設定し、その後、入力データ(ない入力データ*)のベクトルを保持する構造体のそれぞれを持つとしたほうが良いと思います。要素のツリーを定義することは、決して楽しいことではありません。

1

スタックにiDeadEndをインスタンス化し、スタックアドレスへのポインタを取得しています!関数が終了し、スタックが巻き戻されると、iDeadEndのデータは無効になります。

InputData *iDeadEnd = new InputData(1.01f, 0.5f); 
iDeadEnd->deadEnd = true; 
iDeadEnd->parent = current; 
current->children.push_back(iDeadEnd);   

BuildMeshVertices(iDeadEnd, vertices); 

あなたが今持っている問題はiDeadEnd用のメモリは、あなたがそれで終わったときに、明示的に割り当てを解除する必要があるということです。

関連する問題