Can't add object to std::vector

Started by
20 comments, last by Eriond 20 years ago
//********************

// Cube.h

//********************

class Cube
{
public:
	Cube();
	~Cube();
	bool Init();
	bool Draw() const;
private:
	class Vertex
	{
	public:
		Vertex() {}
		Vertex(const D3DXVECTOR3 &position_, const D3DCOLOR &color_)
			: position(position_), color(color_) {}
		D3DXVECTOR3 position;
		D3DCOLOR color;
		static const DWORD FVF;
	};

	IDirect3DVertexBuffer9 *vertexBuffer;
	IDirect3DIndexBuffer9 *indexBuffer;
	D3DCOLOR color;
	float x, y, z;
};

//********************

// Cube.cpp

//********************

#include "Cube.h"

Cube::Cube() : vertexBuffer(0), indexBuffer(0), color(D3DCOLOR_XRGB(0, 0, 0)), 
				x(0), y(0), z(0)
{
}

bool Cube::Init()
{
	scene->GetDevice()->CreateVertexBuffer(24 * sizeof(Vertex),
								0,
								Vertex::FVF,
								D3DPOOL_MANAGED,
								&vertexBuffer,
								0);
	Vertex *vertices;
	vertexBuffer->Lock(0, 0, reinterpret_cast<void **> (&vertices), 0);

	//front

	vertices[0] = Vertex(D3DXVECTOR3(-1.0f, -1.0f, -1.0f), color);
	vertices[1] = Vertex(D3DXVECTOR3(-1.0f,  1.0f, -1.0f), color);
	vertices[2] = Vertex(D3DXVECTOR3(1.0f,  1.0f, -1.0f), color);
	vertices[3] = Vertex(D3DXVECTOR3(1.0f, -1.0f, -1.0f), color);
	//back

	vertices[4] = Vertex(D3DXVECTOR3(-1.0f, -1.0f, 1.0f), color);
	vertices[5] = Vertex(D3DXVECTOR3(1.0f, -1.0f, 1.0f), color);
	vertices[6] = Vertex(D3DXVECTOR3(1.0f,  1.0f, 1.0f), color);
	vertices[7] = Vertex(D3DXVECTOR3(-1.0f,  1.0f, 1.0f), color);
	//top

	vertices[8] = Vertex(D3DXVECTOR3(-1.0f, 1.0f, -1.0f), color);
	vertices[9] = Vertex(D3DXVECTOR3(-1.0f, 1.0f,  1.0f), color);
	vertices[10] = Vertex(D3DXVECTOR3(1.0f, 1.0f,  1.0f), color);
	vertices[11] = Vertex(D3DXVECTOR3(1.0f, 1.0f, -1.0f), color);
	//bottom

	vertices[12] = Vertex(D3DXVECTOR3(-1.0f, -1.0f, -1.0f), color);
	vertices[13] = Vertex(D3DXVECTOR3(1.0f, -1.0f, -1.0f), color);
	vertices[14] = Vertex(D3DXVECTOR3(1.0f, -1.0f,  1.0f), color);
	vertices[15] = Vertex(D3DXVECTOR3(-1.0f, -1.0f,  1.0f), color);
	//left

	vertices[16] = Vertex(D3DXVECTOR3(-1.0f, -1.0f,  1.0f), color);
	vertices[17] = Vertex(D3DXVECTOR3(-1.0f,  1.0f,  1.0f), color);
	vertices[18] = Vertex(D3DXVECTOR3(-1.0f,  1.0f, -1.0f), color);
	vertices[19] = Vertex(D3DXVECTOR3(-1.0f, -1.0f, -1.0f), color);
	//right

	vertices[20] = Vertex(D3DXVECTOR3(1.0f, -1.0f, -1.0f), color);
	vertices[21] = Vertex(D3DXVECTOR3(1.0f,  1.0f, -1.0f), color);
	vertices[22] = Vertex(D3DXVECTOR3(1.0f,  1.0f,  1.0f), color);
	vertices[23] = Vertex(D3DXVECTOR3(1.0f, -1.0f,  1.0f), color);

	vertexBuffer->Unlock();

	scene->GetDevice()->CreateIndexBuffer(36 * sizeof(WORD),
								D3DUSAGE_WRITEONLY,
								D3DFMT_INDEX16,
								D3DPOOL_MANAGED,
								&indexBuffer,
								0);
	WORD* i = 0;
	indexBuffer->Lock(0, 0, reinterpret_cast<void **> (&i), 0);

	// fill in the front face index data

	i[0] = 0; i[1] = 1; i[2] = 2;
	i[3] = 0; i[4] = 2; i[5] = 3;

	// fill in the back face index data

	i[6] = 4; i[7]  = 5; i[8]  = 6;
	i[9] = 4; i[10] = 6; i[11] = 7;

	// fill in the top face index data

	i[12] = 8; i[13] =  9; i[14] = 10;
	i[15] = 8; i[16] = 10; i[17] = 11;

	// fill in the bottom face index data

	i[18] = 12; i[19] = 13; i[20] = 14;
	i[21] = 12; i[22] = 14; i[23] = 15;

	// fill in the left face index data

	i[24] = 16; i[25] = 17; i[26] = 18;
	i[27] = 16; i[28] = 18; i[29] = 19;

	// fill in the right face index data

	i[30] = 20; i[31] = 21; i[32] = 22;
	i[33] = 20; i[34] = 22; i[35] = 23;

	indexBuffer->Unlock();

	return true;
}

Cube::~Cube()
{
	vertexBuffer->Release();
	vertexBuffer = 0;
	indexBuffer->Release();
	indexBuffer = 0;
}

bool Cube::Draw() const
{
	D3DXMATRIX mtrx;
	D3DXMatrixTranslation(&mtrx, x, y, z);
	scene->GetDevice()->SetTransform(D3DTS_WORLD, &mtrx);
	scene->GetDevice()->SetStreamSource(0, vertexBuffer, 0, sizeof(Vertex));
	scene->GetDevice()->SetIndices(indexBuffer);
	scene->GetDevice()->SetFVF(Vertex::FVF);
	scene->GetDevice()->DrawIndexedPrimitive(
					D3DPT_TRIANGLELIST, 
					0,                  

					0,                  
					24,
					0,
					12);
	return true;
}
If I create a Cube like this: Cube cube; cube.Init(); cube.Draw(); Then it works. But if I try to add some cubes to a std::vector the program crashes:
vector<Cube> v;
for (int i = 0; i < 4; ++i)
{
    v.push_back(Cube());
}[/souce]So for some reason I can't have them in a stl-container.

<SPAN CLASS=editedby>[edited by - Eriond on March 21, 2004 3:50:49 PM]</SPAN>
Advertisement
Your class Cube requires a copy ctor.
You could also make the copy ctor private, and store Cube*''s in the vector.
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Actually the culprit looks like that the temporary object created by the Cube() invocation doesn''t actually meet the class invariants implied by the destrctor. In simplier terms, you create a Cube object, and in the constructor all the variables are set to 0 including the the vertexBuffer pointer. You create a copy and stick it in the vector. All is ok up to this point. Then the temporary object you created goes out of scope and needs to be destroyed. The first line in your destructor is vertexBuffer->Release(). This means you''re trying to de-reference a null pointer, which likely is crashing your program.
I tried:
Cube::Cube(const Cube &c){	*vertexBuffer = *c.vertexBuffer;	*indexBuffer = *c.indexBuffer;        /* also tried:        vertexBuffer = 0;        indexBuffer = 0;        */	color = c.color;	x = c.x;	y = c.y;	z = c.z;}
It still crashes.

Edit: Thank you sicrane that solved it. Didn't really think of that

[edited by - Eriond on March 21, 2004 4:06:26 PM]
and don''t forget you must have BOTH a copy constructor AND an assignment operator for types to be managed by the stl.
Instead of creating a new topic. Now I can add Cubes to my vector but when I try to call Init() for all Cubes the program crashes(again). I added a copy ctor and an assignment operator.
Cube::Cube(const Cube &c){	if (this != &c)	{		*vertexBuffer = *c.vertexBuffer;		*indexBuffer = *c.indexBuffer;		color = c.color;		x = c.x;		y = c.y;		z = c.z;	}}Cube &Cube::operator=(const Cube &c){	if (this != &c)	{		*vertexBuffer = *c.vertexBuffer;		*indexBuffer = *c.indexBuffer;		color = c.color;		x = c.x;		y = c.y;		z = c.z;	}	return *this;}
I don't really know how to copy the vertex and indexbuffer :/

[edited by - Eriond on March 21, 2004 4:25:48 PM]
Is there a reason you can''t do the init() work in the ctor?
It still crashes :/ I moved it to an own function before, when I hade multiple ctors.
I think the SiCrance post is still your problem ... I think you are making SHALLOW copies of something (pointing to the same buffers in your copies of the object), but each copy thinks it''s the owner, and so upon destruction, each copy is trying to delete the object it points to (the same object)

hence, when the FIRST object gets DELETED ... all the rest of your objects are becomming INVALID - because the shared buffer has been released.

I didn''t read every line of your code ... but at a glance it seems true ... if that isn''t true - I''ll dig deeper ...

the 2 likely solutions to this problem are:

1. Add some sort of Ref Counting system ... where each items which wants to point to the same buffer adds a ref, and upon delete releases the reference ... then the buffer object destroys itself upon the reference going to 0.

2. Make deep copies, in the copy constructor and assignment operators, make complete duplicates of your object ... in other words go through the WHOLE process of initializing sets of buffers that have the same properties as the originals ... so at the end of your copy constructor, you have 2 seperate objects (and are using twice the buffer / vertex space) ... then each can be safely deleted as needed.
If I use *vb = *c.vb; it crashes, if I use, vb = c.vb; it crashes, if I put the create vertex/indexbuffer code in the copy ctor and assignment operator it crashes. Then I thought of using boost::shared_ptr, but ran into problems directly.
boost::shared_ptr<IDirect3DVertexBuffer9> vertexBuffer;//...device->CreateVertexBuffer(24 * sizeof(Vertex),			0,			Vertex::FVF,			D3DPOOL_MANAGED,			&vertexBuffer, //error here, cant convert to IDirect3DVertexBuffer9**			0);


[edited by - Eriond on March 22, 2004 1:56:30 AM]

This topic is closed to new replies.

Advertisement