3

異なるシステム間でいくつかのコードを変換していますが、c++ベクトルに関して質問があります。

私がこのようなことをした場合:

ヘッダーファイル:

struct Vertex
{
    float x;
    float y;
    float z;
}

struct submesh
{
    Vertex *meshdata;
}

std::vector<submesh> meshes;

C ++ファイルのルーチンでは:

{
    Vertex *data = new Vertex[1024];

    submesh g;
    g.meshdata = data;
    meshes.push_back(g);

    delete [] data;
}

困りますか?私の仮定では、ベクターは、削除を呼び出すと無効になったデータへのポインターを保持することになります。データが最初にコピーされるように、Vertexのコピーコンストラクターを作成する必要がありますか?

追加:

問題は、割り当てられたメモリへのポインタをstd :: vector <>に配置し、ローカルに割り当てられたデータをクリーンアップする方法に関係していました。基本的に、データをベクターにコピーして、コピーをクリーンアップできるようにするにはどうすればよいですか。

元のコードはDirectXにありました。iPhoneに移植しています。元のコードは、以下を使用してルーチンでサブメッシュをローカルに割り当てました。

{
    ID3DXMesh* subMesh = 0;
    D3DXCreateMesh(SubGrid::NUM_TRIS, SubGrid::NUM_VERTS, D3DXMESH_MANAGED, elems, gd3dDevice, &subMesh));

    //
    // ... do some magical things to submesh
    //

    SubGrid g;
    g.mesh = subMesh;
    g.box  = bndBox;
    mSubGrids.push_back(g);
}

ID3DXMeshをベクターに追加する方法を複製しようとしていますが、ルーチンでそのスコープを失います。

D3DXCreateMesh()にアクセスできないため、必要な頂点を割り当て、それらをベクトルにスローして、クリーンアップするだけだと思いました。

申し訳ありませんが、問題はデータのチャンクを割り当て、std :: vector <>にポインタを置き、ローカルに割り当てられたメモリをクリーンアップする方法です。:)

コピーコンストラクターはどこかに書かれなければならないと思いました。どこで、どのようにすればいいのかわからなかった。

サブグリッドは次のようになります。

struct SubGrid
{
    ID3DXMesh* mesh;
    AABB box;

    // For sorting.
    bool operator<(const SubGrid& rhs)const;

    const static int NUM_ROWS  = 33;
    const static int NUM_COLS  = 33;
    const static int NUM_TRIS  = (NUM_ROWS-1)*(NUM_COLS-1)*2;
    const static int NUM_VERTS = NUM_ROWS*NUM_COLS;
};

そして、それらが追加されるベクトルは次のようになります。

std::vector<SubGrid> mSubGrids;
4

3 に答える 3

1

あなたのコードは、シングル スレッド アプリケーションで問題なく表示されます。あなたのコードはdataメモリを一度だけ割り当てますdelete [] data

データが最初にコピーされるように、Vertex のコピー コンストラクターを作成する必要がありますか?

あなたが示したように、あなたのコードはきれいmeshesですdatadatawhen callをコピーするmeshes.push_back(g)つもりだった場合、コードは意図したとおりに動作しません。

std::vector代わりに使用したい場合があります:

struct submesh
{
    std::vector<Vertex> meshdata;
}

vector<submesh> meshes;

void Func()
{
    meshes.emplace_back(submesh());
    meshes.at(0).meshdata.resize(100);
}

STL コンテナーはRAIIイディオムを使用し、メモリの割り当て解除を自動的に管理します。

于 2013-02-10T10:30:29.927 に答える
1

はい、もちろん、ベクトルには削除されたメモリへのポインターがあります。必要なのは次のいずれかです。

  1. submesh(not Vertex).ORのコピー コンストラクターを作成する

  2. submesh(ポインタだけでなく) Vertex の配列を持つように変更します。

コピー コンストラクターは次のように実行できます。

struct submesh
{
    Vertex *meshdata;
    unsigned meshsize;
    submesh(Vertex* v = 0, unsigned s= 0) : meshdata(v), meshsize(s){}
    submesh(const submesh& s)
    {
        if(meshdata) /*we have stored data, delete it.*/ delete(meshdata);
        meshdata = new Vertex[s.meshsize];
        meshsize = s.meshsize;
        memcpy(meshdata, s.meshdata, sizeof(Vertex) * meshsize);
    }
};

確かに、 unique_ptr (c++11 を使用している場合) または古い c++ にはauto_ptrを使用することを強くお勧めします。メモリ管理の悪夢をできるだけ避けるため。

C++ で動的に割り当てられたオブジェクトへのポインターのベクトルを使用するときにメモリ リークを回避する方法を確認してください。

于 2013-02-10T10:21:43.410 に答える
1

必要がないときは直接動的に割り当てないでください。この場合は必要ありません。を使用するのではなく、独自のサブメッシュ データを入力しているためID3DXMesh、そのデータのコンテナーは RAII に準拠している必要があります。これをコーディングする場合、submeshクラスを完全に削除して、次のものを使用します。

// vector containing list of vertices.
typedef std::vector<Vertex> SubMesh;

クラスSubGridは、そのプロパティの 1 つとしてsubmeshコレクションを保持する単純なコンテナになることができます。AABBボックス オブジェクトのクラスもあることに気付きました。あなたはそれを内部に保ち続けますSubGrid。ここで作業する必要はあまりないので、進行中にこれらのいくつかを作成していますが、次のようなものです。

// a simple 3-value triplet of floats
struct Vertex
{
    float x,y,z;
};

// a Submesh is an arbitrary collection of Vertex objects.
typedef std::vector<Vertex> SubMesh;

// I'm defining AABB to be an 8-vertex object. your definition
//  is likely different, but I needed something to compile with =)
typedef Vertex AABB[8];

class SubGrid
{
public:
    SubGrid() {};

    // comparator for container ordering
    bool operator <(const SubGrid&);

    // submesh accessors
    void setSubmesh(const SubMesh& mesh) { submesh = mesh;}
    SubMesh& getSubmesh() { return submesh; }
    const SubMesh& getSubmesh() const { return submesh; }

    // box accessors
    AABB& getBox() { return box; }
    const AABB& getBox() const { return box;}

private:
    SubMesh submesh;
    AABB box;
};

// arbitrary collection of SubGrid objects
typedef std::vector<SubGrid> SubGrids;

これをグローバルSubGridコレクションgに追加する場合、いくつかの可能性があります。これを行うことができます:

// declared globally 
Subgrids g;

// in some function for adding a subgrid item
SubGrid subgrid;
AABB& box = subgrid.getBox();
SubBesh& submesh = subgrid.getSubmesh();

// ... initialize your box and submesh data ...

g.push_back(subgrid);

しかし、大量のデータをコピーすることになります。メモリアクセスを強化するには、代わりに常にこれを実行できます。

// push an empty SubGrid first, then set it up in-place
g.push_back(SubGrid());
Subgrid& subgrid = *(g.back());
AABB& box = subgrid.getBox();
SubMesh& submesh = subgrid.getSubmesh();

//... initialize your box and submesh data ...

SubGridこれにより、グローバル コレクションに追加されたへの参照が確立され、その場で変更できるようになります。これは、可能なセットアップ オプションの 1 つにすぎません。ツールチェーンに C++11 が含まれている場合 (MacOS または iOS でこれを実行している場合は、Apple LLVM 4.2 の clang が C++11 準拠でかなり優れているため、そうする可能性が高い)、これに注意してください。move-constructorsmove-assignment-operatorsを賢明に使用すると、さらに効率的になります。

最も重要なことは、newまたはdelete見られることではありません。

とにかく、これがあなたにいくつかのアイデアを与えることを願っています。

于 2013-02-10T19:16:51.830 に答える