将指针推入c++向量,并进行清理

Pushing pointers into c++ vectors, and cleanup

本文关键字:向量 指针 c++      更新时间:2023-10-16

我正在不同系统之间转换一些代码,我有一个关于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;
}

我会有麻烦吗?我的假设是,一旦我在向量上调用delete,向量将包含一个指向不再有效的数据的指针。我是否需要为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;

在不需要的时候不要直接动态分配,在这种情况下你不需要。由于您要填充自己的子网格数据,而不是使用ID3DXMesh,因此该数据的容器应该符合RAII。如果我对此进行编码,我会完全删除submesh类,只使用:

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

然后,您的SubGrid类可以成为一个简单的容器,作为其属性之一,它包含一个submesh集合。我注意到您还有一个用于box对象的类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的引用,然后允许您就地修改它。这只是众多可能的设置选项之一。需要注意的是,如果你的工具链中有C++11(如果你在MacOS或iOS上这样做,你可能会这样做,因为Apple LLVM 4.2的clang在C++11合规性方面非常好),明智地使用移动构造函数移动赋值运算符可以提高效率。

最重要的是,不能看到newdelete

不管怎样,我希望这能给你一些想法。

您的代码在单线程应用程序中看起来不错。您的代码只分配data内存一次,分配delete [] data内存一次。

我是否需要为Vertex编写一个复制构造函数,以便首先复制数据?

如图所示,您的代码是干净的,meshes只指向已分配的data。如果你想在调用meshes.push_back(g)时复制data,那么你的代码并没有达到你的目的。

您可能需要使用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习惯用法,它自动为您管理内存释放。

当然,向量将有一个指向已删除内存的指针。您需要的是:

  1. submesh(而非Vertex)创建复制构造函数。OR

  2. submesh更改为具有顶点数组(而不仅仅是指针)。

复制构造函数可以这样做:

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

当然,对于旧的c++,强烈建议使用unique_ptr(如果使用c++11)或auto_ptr。尽可能避免内存管理的噩梦。

检查在C++中使用指向动态分配对象的指针向量时如何避免内存泄漏?