When I debug my program, I get this error:
Unhandled exception at 0x004d2776 in engine.exe: 0xC0000005: Access violation reading location 0xccccccd0.

This is the stack trace:

>	engine.exe!CEntityController::SpawnEntities()  Line 18 + 0x24 bytes	C++
 	engine.exe!CEntityController::Start()  Line 50	C++
 	engine.exe!DarkGDK()  Line 21	C++
 	engine.exe!_WinMain@16()  + 0x13 bytes	C++
 	engine.exe!__tmainCRTStartup()  Line 263 + 0x1b bytes	C

This is the code for SpawnEntities( ):

void CEntityController::SpawnEntities( )
{
	for( int i = 0; i < m_vEntities.size( ); ++i )
		m_vEntities[i]->Spawn( );
}

At the moment there isn't actually any code inside spawn, so it must be either m_vEntities isn't initialized, or m_vEntities isn't initialized. I think m_vEntities gets initialized automatically when CEntityController gets constructed. Here is where entities get added to m_vEntities:

CBaseEntity::CBaseEntity( )
:m_sModelName( "" ), m_nModelID( 0 ), m_vOrigin( VEC( 0.0f, 0.0f, 0.0f ) ),
m_bOriginSet( false )
{
	gpGlobals.controller.AddEntity( this );
}

Here is the code for AddEntity( ):

void CEntityController::AddEntity( CBase *pEntity )
{
	m_vEntities.push_back( pEntity );
}

I've looked around in my code, and I can't find any variables that have been assigned that address(0xccccccd0).

Here is the code for my CBaseEntity class, since attaching files isn't working:

header:

#ifndef BASEENTITY_H
#define BASEENTITY_H
#include "defines.h"
#include "cbase_class.h"
#include "string.h"
#include "vector.h"
#include "entitycontroller.h"

class CBaseEntity : public CBase{
	STR m_sModelName;
	STR m_sName;
	unsigned int m_nModelID;
	VEC m_vOrigin;
	bool m_bOriginSet;
public:
	DECLARE_CLASS( CBaseEntity, CBase );

	CBaseEntity( );
	~CBaseEntity( );

	STR GetModelName( );
	unsigned int GetModelID( );

	void SetModel( char *pFileName );
	void SetModelDebugMode( );
	void SetOrigin( VEC vOrigin );
	void SetName( char *pName );

	virtual void Think( );
	virtual void Spawn( );
	virtual void Activate( );
	virtual void Delete( );
};

#endif //BASEENTITY_H

source file:

//---------------------------------------------//
// Copyright Tom Tetlaw(C) 2010
//-----------------------------------------//

#include "DarkGDK.h"
#include "baseentity.h"
#include "globals.h"

CBaseEntity::CBaseEntity( )
:m_sModelName( "" ), m_nModelID( 0 ), m_vOrigin( VEC( 0.0f, 0.0f, 0.0f ) ),
m_bOriginSet( false )
{
	gpGlobals.controller.AddEntity( this );
}

CBaseEntity::~CBaseEntity( )
{
	gpGlobals.model_id_manager.RemoveID( );
}

STR CBaseEntity::GetModelName( )
{
	return m_sModelName;
}

unsigned int CBaseEntity::GetModelID( )
{
	return m_nModelID;
}

void CBaseEntity::SetModel( char *pFileName )
{
	if( dbObjectExist( m_nModelID ) )
	{
		dbDeleteObject( m_nModelID );
	}

	m_nModelID = gpGlobals.model_id_manager.GetNextID( );
	dbLoadObject( pFileName, m_nModelID );
}

void CBaseEntity::SetModelDebugMode( )
{
	if( m_sModelName.PtrValue( ) == "models/debug_mode.x" )
	{
		dbDeleteObject( m_nModelID );
		return;
	}
	SetModel( "models/debug_mode.x" );
}

void CBaseEntity::SetOrigin( VEC vOrigin )
{
	if( m_bOriginSet )
		return;
	m_vOrigin = vOrigin;
	dbPositionObject( m_nModelID, m_vOrigin.x, m_vOrigin.y, m_vOrigin.z );
	m_bOriginSet = true;
}

void CBaseEntity::Think( )
{
}

void CBaseEntity::Spawn( )
{
	SetModelDebugMode( );
}

void CBaseEntity::Activate( )
{
}

void CBaseEntity::Delete( )
{
}

void CBaseEntity::SetName( char *pName )
{
	m_sName = pName;
}

I just need to find out why it's giving me that error, your time and effort to help me will be appreciated. :)

>> I've looked around in my code, and I can't find any variables that have been assigned that address(0xccccccd0).

In MS VS debug builds, if you don't explicitly initialize a pointer that is on the stack, it gets initialized with the value 0xcccccccc. So make sure you don't use uninitialized pointers and watch out for pointers having the value 0xcccccccc rather than 0xccccccd0.

0xccccccd0 is rather a side-effect of the root cause (access through uninitialized pointer) i.e. most likely you won't be finding pointers with that value.

Edited 6 Years Ago by mitrmkar: i

Comments
Nice

Hey Tom!

You said that this portion of code was causing the runtime error:

void CEntityController::SpawnEntities( )
{
	for( int i = 0; i < m_vEntities.size( ); ++i )
		m_vEntities[i]->Spawn( );
}

Bearing that in mind, have you tried using an iterator to dereference the vector, or perhaps even using .at() which is more type-safe than dereferencing the vector directly??
Might be worth a try, .at() should throw an exception if there's a problem with one of the items that you're dereferencing. That might shed some light on the problem.

You've also said that the CEntity::Spawn method doesn't do anything ATM, so we know that's not the problem. Plus CEntity::Spawn is not listed in the call stack, so we can definitely rule that out.

Which leaves the vector and the items it contains (Pointers to CEntity objects wasn't it?). I suspect it's most likely that one or more of the objects/pointers in the vector have not been initialised correctly.

I also noticed that the CEntityController::Start function is listed further up the stack-trace... Is there any chance that there is something going awry somewhere in the Start function which could be causing the problems you're seeing in the SpawnEntities function? It could even be something that gets set-up before the start function is called and that the start function is merely triggering the bug.

I'd say take a look at any code which deals with the vector of entities, starting with the very first bit of code that initialises the vector, and then any subsequent uses of the vector (adding entities to the vector etc.) right up until the code in the start function.

If need be, put breakpoints on any lines that do anything with the vector and keep checking the state of the vector and it's contents. That should give you all the answers you need.

With a little patience and some debugging prowess, I think you'll get to the bottom of this in no time! I have a feeling this is gonna be one of those bugs where you'll just want to kick yourself when you realise what it is. Most of my bugs tend to be of that variety! heh heh!

Anyways, all the best with the debugging!
Cheers for now,
Jas.

Hey Jason :)
Using .at( ) didn't work, it gave me the same error. Mabey I'm doing it wrong? This is how I did it: m_vEntities.at( i )->Spawn( ) All Start( ) does is call SpawnEntities( ) and ActivateEntities( ), and the one that gets called first is SpawnEntities( ) which is the one throwing the error, so I don't think it's in Start( ).

I don't know if m_vEntities is initialized or not, but doesn't the default constructor get called anyway if it's a member of a class that gets constructed? The constructor doesn't actually have anything in it about m_vEntities, so that might be the problem.

At the moment, I'm only adding one thing to the vector just to test it, with gpGlobalFunctions.Spawn( "debug_entity_test", "test" );
Here is that function:

void CGlobalFunctions::Spawn( char *pName, char *pEntityName )
{
	if( pName == "debug_entity_test" )
	{
		CBaseEntity eTest;
		eTest.SetName( "test" );
	}

	if( pName == "debug_animating_entity_test" )
	{
		CBaseAnimating eTest;
		eTest.SetName( pEntityName );
	}
}

EDIT: I looked at every part of code about the vector with the debugger, and when I hover over the m_vEntities with my mouse, it shows me that the entity has been put into the vector, then when I look into the entity, it says there's a variable called _vfptr(i didn't put that there) which has the value 0xcccccccc, and the member of the entity, "m_sEntityName" has a member called m_sValue which has the value <Bad Ptr>.

I don't know how to fix this or what it means, but it looks like it could be the source of the problem.

Edited 6 Years Ago by tomtetlaw: n/a

Well, I fixed it. I did it by making the variables inside gpGlobalFunctions.Spawn( ) pointers, and initializing them with new.

Now I have a different problem, here is the error:

------ Build started: Project: engine, Configuration: Debug Win32 ------
Compiling...
test.cpp
c:\documents and settings\tom\my documents\visual studio 2008\projects\engine\engine\test.cpp(12) : warning C4244: 'argument' : conversion from 'double' to 'float', possible loss of data
c:\documents and settings\tom\my documents\visual studio 2008\projects\engine\engine\test.cpp(32) : error C2143: syntax error : missing ';' before '.'
c:\documents and settings\tom\my documents\visual studio 2008\projects\engine\engine\test.cpp(32) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c:\documents and settings\tom\my documents\visual studio 2008\projects\engine\engine\test.cpp(32) : error C2371: 'gpGlobalFunctions' : redefinition; different basic types
        c:\documents and settings\tom\my documents\visual studio 2008\projects\engine\engine\globals.h(32) : see declaration of 'gpGlobalFunctions'
Generating Code...
Compiling...
main.cpp
Generating Code...
Build log was saved at "file://c:\Documents and Settings\tom\My Documents\Visual Studio 2008\Projects\engine\engine\Debug\BuildLog.htm"
engine - 3 error(s), 1 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

This is coming from this file:

test.cpp

#include "cbase.h"

class CTestEntity : public CBaseEntity{
public:
	CTestEntity( );
	void Think( );
	void Spawn( );
};

CTestEntity::CTestEntity( )
{
	SetNextThink( gpGlobals.curtime + 1.0 );
}

void CTestEntity::Spawn( )
{
	VEC vOrigin;
	vOrigin.x = 0.0f;
	vOrigin.y = 0.0f;
	vOrigin.z = 0.0f;
	SetOrigin( vOrigin );
}

void CTestEntity::Think( )
{
	dbPositionObject( GetModelID( ), GetOrigin( ).x + 0.3f, GetOrigin( ).y, GetOrigin( ).z );
	SetNextThink( gpGlobals.curtime + 1.0f );
}

CTestEntity eRegEntity;
gpGlobalFunctions.RegisterEntity( eRegEntity ); //this line

It's telling me that gpGlobalFunctions isn't defined, even though I included it in cbase.h(it's inside globals.h)

here is cbase.h:

//---------------------------------------------//
// Copyright Tom Tetlaw(C) 2010
//-----------------------------------------//

#ifndef CBASE_H
#define CBASE_H

#include "DarkGDK.h"
#include "cbase_class.h"
#include "baseentity.h"
#include "entitycontroller.h"
#include "globals.h"

#endif //CBASE_H

here is globals.h:

//---------------------------------------------//
// Copyright Tom Tetlaw(C) 2010
//-----------------------------------------//

#ifndef GLOBALS_H
#define GLOBALS_H

#include "timer.h"
#include "id_manager.h"
#include "entitycontroller.h"
#include "string.h"
#include <vector>

//class CEntityController;

typedef struct{
	float curtime;
	float curtime_next_tick;
	CTimer timer;
	IDM model_id_manager;
	IDM	anim_id_manager;
	CEntityController controller;
	std::vector<CBase*> entities;
}CGlobals;

typedef struct{
	void Spawn( char *pName, char *pEntityName );
	void RegisterEntity( CBase *pEntity );
}CGlobalFunctions;

extern CGlobals gpGlobals;
extern CGlobalFunctions gpGlobalFunctions;


#endif //GLOBALS_H

globals.cpp:

//---------------------------------------------//
// Copyright Tom Tetlaw(C) 2010
//-----------------------------------------//

#include "globals.h"
#include "string.h"
#include "baseentity.h"
#include "baseanimating.h"

void CGlobalFunctions::Spawn( char *pName, char *pEntityName )
{
	if( pName == "debug_entity_test" )
	{
		CBaseEntity *eTest = new CBaseEntity;
		eTest->SetName( "test" );
	}

	if( pName == "debug_animating_entity_test" )
	{
		CBaseAnimating *eTest = new CBaseAnimating;
		eTest->SetName( pEntityName );
	}
}

void CGlobalFunctions::RegisterEntity( CBase *pEntity )
{
	gpGlobals.entities.push_back( pEntity );
}

CGlobals gpGlobals;
CGlobalFunctions gpGlobalFunctions;

you help will and has been appreciated :)

Well, I fixed it. I did it by making the variables inside gpGlobalFunctions.Spawn( ) pointers, and initializing them with new.

That sounds good i.e. you are not anymore storing pointers to stack-based objects in the vector. Actually you are allocating those objects with new .

Then regarding the errors ...
test.cpp ...

<snip>

CTestEntity::CTestEntity( )
{
    // force the value to float (otherwise it would be double)
    SetNextThink( gpGlobals.curtime + 1.0f);
}

<snip>

CTestEntity eRegEntity; // this line is OK
// But the following must be moved inside a function
gpGlobalFunctions.RegisterEntity( eRegEntity );

The header files you posted seem to be OK in terms of having #include guards, so the compiler probably got mixed up because of that outside-function usage of gpGlobalFunctions.RegisterEntity(...) you have there. So make the changes, re-compile and see what you get.

One thing for you to notice, you seem to be using constructs as

void some_func(char * p1)
{
    if(p1 == "debug_entity_test")
    {
        // something here
    }
    else if(p1 == "debug_entity_test_other")
    {
        // something here too
    }
}

That may work for you as intended and probably has been doing so, but when you compare C-style strings, use strcmp() for figuring out whether two strings match or not, so

void some_func(char * p1)
{
    if(0 == strcmp(p1, "debug_entity_test"))
    {
        // p1 equals "debug_entity_test"
    }
}

There are other strcmp() -family functions also, maybe look them up.

Edited 6 Years Ago by mitrmkar: ICODE

How will I be able to do entities like that if I have to put that inside a function? I planned to have the user enter all the class stuff into a .cpp file, then write that code so their entity is able to be spawned by gpGlobalFunctions.Spawn( ). I know this can be done, I've seen it before in the Source Engine.

How will I be able to do entities like that if I have to put that inside a function?

That's a difficult one to answer because there is a apparently a lot involved and not knowing the rest of code you already have.

But how about if you step back for a little while and start a new small project that involves a simple object hierarchy (say Base, Entity, TestEntity) and some global object storage.

- The global object storage would maintain/keep track of the objects of these classes (using e.g. vector<Base *> as you already seem to have).
- All of the objects would be allocated dynamically (that is, using new )
- Upon allocation of an object, a pointer to it would be stored in the global storage
- All of the objects would be deleted/destructed (using delete )
- Upon deletion of an object, the pointer to it in the global storage would be removed

I think that might be quite useful in realizing how to design this very basic object management scenario and have it work reliably. Because now it seems, that you are running into trouble because you don't yet know how to do that.

PS. In the previous post I commented that

CTestEntity eRegEntity; // this line is OK

However, that's actually not OK, if you store a pointer to it via the constructor and later on try to delete the object via the pointer. And moreover, you having that line there is in contradiction to what you said about initializing all the objects with new . That object is not allocated on the heap (using new), so you must not try delete it.

This article has been dead for over six months. Start a new discussion instead.