Pushing pointers to C ++ vectors and cleaning up

I am converting some code between different systems and I have a question regarding C ++ vectors.

If I do something like this:

In the header file:

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

struct submesh
{
    Vertex *meshdata;
}

std::vector<submesh> meshes;

      

In a subroutine in a C ++ file:

{
    Vertex *data = new Vertex[1024];

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

    delete [] data;
}

      

Will I have problems? My guess is that the vector will contain a pointer to data that is no longer valid as soon as I call delete . Do I need to write a copy constructor for Vertex to copy the data first?

Additionally:

The question was more to do with how I put a pointer to the allocated memory in a std :: vector <> and still clear the locally allocated data. Basically how do I copy the data into a vector so that I can clear my copy.

The source code was in DirectX. I am transferring it to iPhone. The source code has localized the subtitle in a subroutine using:

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

      

I am trying to duplicate the way I add ID3DXMesh to a vector and then lose it in a subroutine.

Since I don't have access to D3DXCreateMesh (), I figured I just selected the vertices I needed, dumped them into the vector, and cleaned up.

Sorry, I wanted to keep minuscule verbose data out of it, as the question is how to allocate a chunk of data, put a pointer in std :: vector <> and then clear the locally allocated memory, :)

I assumed the copy constructor must be written somewhere. I was just not sure where or how.

The count looks like this:

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

      

And the vector they add looks like this:

std::vector<SubGrid> mSubGrids;

      

+3


source to share


3 answers


Don't dynamically dynamically allocate when you don't need it, in which case you won't. Since you are filling in your own sumesh data, not using ID3DXMesh

, the container of that data must be RAII compliant. If I were to code this, I would completely remove the class submesh

and just use:

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

      

Then your class SubGrid

will become a simple container that stores a collection as one of its properties submesh

. I noticed that you also have a class AABB

for the box object. You keep holding it inside SubGrid

. I have no work to do here, so I do some of them as I go, but something like the following:

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

      

When adding this to the global collection SubGrid

g

, you have several options. You could just do this:

// 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);

      



But you will be copying a lot of data. To leverage memory access, you can always do this:

// 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 ...

      

This will link to the SubGrid

one you just added to the global collection, then allow you to modify it in place. This is just one of several possible configuration options. It should be noted that if you have C ++ 11 in your toolchain (and if you are doing it on macOS or iOS, most likely the same as Apple's LLVM 4.2 clang does pretty well with C ++ 11), it might get even more efficient with judicious use of move-constructors and move-assign statements .

The most important thing is not to see new

or delete

.

Anyway, hopefully this gives you some ideas.

+1


source


Yes, of course the vector will have a pointer to remote memory. You need to either:

  • Create a copy constructor for submesh

    (not Vertex

    ). OR

  • Change submesh

    to have an array of vertices (not just a pointer).

The copy constructor can be done like this:



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

      

It is of course recommended to use unique_ptr (if you are using C ++ 11) or auto_ptr for old C ++. To avoid the nightmare of memory management, as much as possible.

Check How to avoid memory leaks when using a vector of pointers to dynamically allocated objects in C ++?

+1


source


Your code looks great in a single threaded application. Your code data

only allocates once and delete [] data

once.

Do I need to write a copy constructor for Vertex to copy data first?

Your code will be clean as shown, meshes

only points to the highlighted one data

. If you want to copy data

when called meshes.push_back(g)

, then your code won't do what you meant.

You can use instead std::vector

:

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

vector<submesh> meshes;

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

      

The STL container uses RAII , it automatically manages the deallocation of memory.

+1


source







All Articles