Вставка указателей в векторы C ++ и очистка

Я конвертирую некоторый код между различными системами, и у меня есть вопрос относительно векторов 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;
}

Буду ли я в беде? Я предполагаю, что вектор будет содержать указатель на данные, которые больше не действительны после того, как я позвонил удалять в теме. Нужно ли писать конструктор копирования для темя чтобы данные копировались первыми?

Дополнительно:

Вопрос был больше связан с тем, как поместить указатель на выделенную память в 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;

3

Решение

Не делайте прямого динамического выделения, когда вам это не нужно, и в этом случае вам это не нужно. Так как вы заполняете свои собственные данные подсетей, а не используете ID3DXMesh, контейнер этих данных должен быть RAII-совместимым. Если бы я кодировал это, я бы удалил submesh Класс целиком и просто использовать:

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

Ваш SubGrid класс может стать простым контейнером, который содержит в качестве одного из своих свойств 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 просто добавляется в глобальную коллекцию, а затем позволяет изменять ее на месте. Это всего лишь один из нескольких возможных вариантов настройки. Следует отметить, что если у вас есть C ++ 11 в вашем наборе инструментов (и если вы делаете это на MacOS или iOS, то, скорее всего, так и есть, поскольку Clang от Apple LLVM 4.2 довольно хорош в отношении соответствия C ++ 11), это может стать еще более эффективным при разумном использовании двигаться-конструкторы а также въезд назначение-операторы.

Самое главное, не new или же delete чтобы увидеть.

Во всяком случае, я надеюсь, что это дает вам некоторые идеи.

1

Другие решения

Ваш код отлично выглядит в однопоточном приложении. Ваш код только выделить data память один раз и delete [] data один раз.

Нужно ли мне писать конструктор копирования для Vertex, чтобы данные копировались первыми?

Ваш код чистый, как вы показали, meshes указывает только на выделенные data, Если вы хотели скопировать data когда звоните 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 идиома, он управляет освобождением памяти для вас автоматически.

1

Да, конечно, вектор будет иметь указатель на удаленную память. То, что вам нужно, это либо:

  1. Создать конструктор копирования для submesh (не Vertex).ИЛИ ЖЕ

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

Наверняка это очень рекомендуется использовать unique_ptr (если вы используете c ++ 11) или auto_ptr для старого с ++. Чтобы избежать кошмара управления памятью как можно больше.

Проверьте Как избежать утечек памяти при использовании вектора указателей для динамически размещаемых объектов в C ++?

1
По вопросам рекламы [email protected]