Я конвертирую некоторый код между различными системами, и у меня есть вопрос относительно векторов 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;
Не делайте прямого динамического выделения, когда вам это не нужно, и в этом случае вам это не нужно. Так как вы заполняете свои собственные данные подсетей, а не используете 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
чтобы увидеть.
Во всяком случае, я надеюсь, что это дает вам некоторые идеи.
Ваш код отлично выглядит в однопоточном приложении. Ваш код только выделить 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 идиома, он управляет освобождением памяти для вас автоматически.
Да, конечно, вектор будет иметь указатель на удаленную память. То, что вам нужно, это либо:
Создать конструктор копирования для submesh
(не Vertex
).ИЛИ ЖЕ
+ Изменить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 для старого с ++. Чтобы избежать кошмара управления памятью как можно больше.