Archived

This topic is now archived and is closed to further replies.

Eriond

Can't add object to std::vector

Recommended Posts

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

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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
and don''t forget you must have BOTH a copy constructor AND an assignment operator for types to be managed by the stl.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
Um...why are you doing the address of? Of course it''s giving you an error there.

Off the top of my head, I''m almost positive boost::shared_ptr will implictly cast.

Share this post


Link to post
Share on other sites
quote:
Original post by Eriond
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;
}
}



checking for "this != &c" doesn''t achieve anything. It''s a newly constructed Cube so ''this'' can''t possibly be the same as the Cube being passed to it. In the assignment operator checking the same is just an optimisation and shouldn''t be relied upon to keep code safe. It doesn''t have to be there for either of them.

Share this post


Link to post
Share on other sites
Use the shared_ptr. In the destructor check whether it is the only one pointing to the vertexBuffer before calling Release

ie

if(vertexBuffer.unique())
vertexBuffer->Release();
if(indexBuffer.unique())
indexBuffer->Release();


This will mean that when the copy constructor is called the vertexBuffer will be shared between more than one Cube. When the destructor is called it will only be Release''d by the last Cube.

Share this post


Link to post
Share on other sites
why the shared ptr? the dx interfaces are all refcounted, aren''t they?

in the copy constructor, copy the pointers of the buffer-interfaces, and then do an ->AddRef() to both

in the destructor, do a ->Release() to both


that should do the job.




If that''s not the help you''re after then you''re going to have to explain the problem better than what you have. - joanusdmentia

davepermen.net

Share this post


Link to post
Share on other sites
I don't know much about dx

If that's the case then davepermen has the winning ticket. Forget the shared_ptr stuff.

edit: pluralised dave's name

[edited by - petewood on March 22, 2004 5:51:48 AM]

Share this post


Link to post
Share on other sites
Exactly, as davepermen says, you should do an vertexbuffer->AddRef() in the copy ctor and the assignment operator, that way you need only copy the ptr.
[EDIT]name[/EDIT]

[edited by - amag on March 22, 2004 7:22:17 PM]

Share this post


Link to post
Share on other sites
*wisper* my name is davepermen *cough*



:D


ps.: i''m trained to this:D




If that''s not the help you''re after then you''re going to have to explain the problem better than what you have. - joanusdmentia

davepermen.net

Share this post


Link to post
Share on other sites
Now when you talk about AddRef() I remember that. Thank you very much, I'll test when I get home from school :D

Edit: Now my copy ctor, assignment operator and destructor looks like:
Cube::Cube(const Cube &c)
{
vertexBuffer = c.vertexBuffer;
indexBuffer = c.indexBuffer;
vertexBuffer->AddRef();
indexBuffer->AddRef();
color = c.color;
x = c.x;
y = c.y;
z = c.z;
}

Cube &Cube::operator=(const Cube &c)
{
vertexBuffer = c.vertexBuffer;
indexBuffer = c.indexBuffer;
vertexBuffer->AddRef();
indexBuffer->AddRef();
color = c.color;
x = c.x;
y = c.y;
z = c.z;
return *this;
}

Cube::~Cube()
{
if (vertexBuffer)
{
vertexBuffer->Release();
vertexBuffer = 0;
}
if (indexBuffer)
{
indexBuffer->Release();
indexBuffer = 0;
}
}
It still crashes

[edited by - Eriond on March 22, 2004 10:57:45 AM]

[edited by - Eriond on March 22, 2004 3:59:35 PM]

Share this post


Link to post
Share on other sites
first:
where does it crash (debuggin?)

second:

i always made operator= in that style:


Type& operator=(const Type& other) {
if(this!=&other) {
if(this->refCounted) this->refCounted->release(); // we lose the old one

this = other.refCounted; // we move on with the new one

if(this->refCounted) this->refCounted->addRef(); // we grab the new one

}
return *this;
}





If that''s not the help you''re after then you''re going to have to explain the problem better than what you have. - joanusdmentia

davepermen.net

Share this post


Link to post
Share on other sites
It crashes on this line:
scene->GetDevice()->CreateVertexBuffer(24 * sizeof(Vertex),
0,
Vertex::FVF,
D3DPOOL_MANAGED,
&vertexBuffer,
0);
I get "Unhandled exception at 0x00426726 in bla.exe: 0xC0000005: Access violation reading location 0x00000000". And it points at the function:
IDirect3DDevice9 *Scene::GetDevice()
{
return device; // this line!

}
Device is a private member in Scene(a IDirect3DDevice9 *). If I create a Cube object like this: Cube cube;
cube.Draw();Everything works as it should.

[edited by - Eriond on March 22, 2004 4:01:42 PM]

Share this post


Link to post
Share on other sites
Are you trying to call GetDevice through a NULL pointer? It looks that way from the error you''re getting.

Hint: when it crashes, go into the debugger and look at the Variables window. Check the value of ''this''.

Share this post


Link to post
Share on other sites
I got it to work now. I fixed the copy ctor and assignment operator of Cube, and moved some code from another ctor to a new function.

Share this post


Link to post
Share on other sites