Alright, so I'm currently working on a game and ran into a memory issue after refactoring some of the code today.
It uses a component based design and I was modifying how the components were allocated and passed off to entities. Originally some components were allocated as member variables within the entities but now I want to have them allocated elsewhere and passed off to the entity via pointer.
You can see how I implemented this below with sample code from my project. I essentially iterate through all the entities and allocate the components for them. The problem is I'm hitting a access violation at the first line of "starting up" the "instanceObject" on the 6th iteration and have no idea why. Using the debugger, it doesn't look like any of the variables point to a invalid address.
Here is what I'm doing to create the entities and components.
for (unsigned int i = 0; i < 512; ++i) {
InstanceObject* _pInstanceObject = new InstanceObject;
// Initialize temporary variables
XMFLOAT3 _position, _rotation;
float _angle = (i / 512.0f) * (2.0f * XM_PI),
_scale = (float)pResourceManager->numberGenerator.GetInt(50, 5);
_position.x = 100000.0f * cos(_angle) + pResourceManager->numberGenerator.GetInt(50000, -25000);
_position.y =(float) pResourceManager->numberGenerator.GetInt(50000, -25000);
_position.z = 100000.0f * sin(_angle) + pResourceManager->numberGenerator.GetInt(50000, -25000);
_rotation.x = (XM_PI * 2) * (pResourceManager->numberGenerator.GetInt(100, 0) / 100.0f);
_rotation.y = (XM_PI * 2) * (pResourceManager->numberGenerator.GetInt(100, 0) / 100.0f);
_rotation.z = (XM_PI * 2) * (pResourceManager->numberGenerator.GetInt(100, 0) / 100.0f);
// Set component's state using the temporary variables.
_pInstanceObject->StartUp(&_position,
&_rotation,
&XMFLOAT3(_scale, _scale, _scale),
&XMFLOAT3(0.0f, 0.0f, 1.0f),
&XMFLOAT3(1.0f, 0.0f, 0.0f),
&XMFLOAT3(0.0f, 1.0f, 0.0f)
);
// Hand pointer of the component to entity.
// Entity will handle deallocating component
}
And here is the relevant code from the component.
class InstanceObject {
private:
XMVECTOR anteriorAxis,
lateralAxis,
normalAxis,
position,
rotationQuaternion,
scale;
XMMATRIX translationMatrix,
rotationMatrix,
scaleMatrix;
void SetAnteriorAxis(const XMFLOAT3 *_anteriorAxis) { anteriorAxis = XMLoadFloat3(_anteriorAxis); }
void SetLateralAxis(const XMFLOAT3 *_lateralAxis) { lateralAxis = XMLoadFloat3(_lateralAxis); }
void SetNormalAxis(const XMFLOAT3 *_normalAxis) { normalAxis = XMLoadFloat3(_normalAxis); }
public:
InstanceObject(void) { }
InstanceObject(const InstanceObject& _object) : anteriorAxis(_object.anteriorAxis), lateralAxis(_object.lateralAxis),
normalAxis(_object.normalAxis), position(_object.position), rotationQuaternion(_object.rotationQuaternion), scale(_object.scale),
translationMatrix(_object.translationMatrix), rotationMatrix(_object.rotationMatrix), scaleMatrix(_object.scaleMatrix) {}
~InstanceObject(void) { }
bool StartUp(const XMFLOAT3 *_position, const XMFLOAT3 *_rotation, const XMFLOAT3 *_scale,
const XMFLOAT3 *_lookAxis, const XMFLOAT3 *_strafeAxis, const XMFLOAT3 *_upAxis);
void SetPosition(const XMFLOAT3* _position) { position = XMLoadFloat3(_position); }
void SetRotationQuaternion(const XMFLOAT3 *_rotation) { rotationQuaternion = XMQuaternionRotationRollPitchYaw(_rotation->x, _rotation->y, _rotation->z); }
void SetScale(const XMFLOAT3 *_scale) { scale = XMLoadFloat3(_scale); }
}
bool InstanceObject::StartUp(const XMFLOAT3 *_position, const XMFLOAT3 *_rotation, const XMFLOAT3 *_scale,
const XMFLOAT3 *_lookAxis, const XMFLOAT3 *_strafeAxis, const XMFLOAT3 *_upAxis) {
SetPosition(_position);
SetRotationQuaternion(_rotation);
SetScale(_scale);
SetAnteriorAxis(_lookAxis);
SetLateralAxis(_strafeAxis);
SetNormalAxis(_upAxis);
return true;
}
Any idea of what could be causing this behavior and how should I fix it?
I believe the issue is that the XMVECTOR in your InstanceObject class need to be 16 byte aligned, and the new operator won't guarantee this for you. You can add a quick check into your code to confirm - check whether the InstanceObject pointer & 0xF is non zero in the iteration in which it crashes.
If that is the case you can write a custom allocator that guarantees the right alignment and use placement new.
It seems to be a fairly common problem with XMVECTOR when used as a member (here's an existing Connect bug report on this issue, there are a few web pages if you search).
If you just want to fix it quickly to let you get on with other things, you can add a static operator new and delete to your class declaration implemented something like the following snippet:
void* InstanceObject::operator new( size_t size )
{
// _aligned_malloc is a Microsoft specific method (include malloc.h) but its
// straightforward to implement if you want to be portable by over-allocating
// and adjusting the address
void *result = _aligned_malloc( size, 16 );
if( result )
return result;
throw std::bad_alloc();
}
void InstanceObject::operator delete( void* p )
{
if( p ) _aligned_free(p);
}
If the InstanceObject share a common lifetime you could replace the use of _aligned_malloc with your own aligned arena allocator and make the delete a no-op to improve efficiency.
You're taking the addresses of temporaries! That's not even allowed!
// Set component's state using the temporary variables.
_pInstanceObject->StartUp(&_position,
&_rotation,
&XMFLOAT3(_scale, _scale, _scale), // not valid
&XMFLOAT3(0.0f, 0.0f, 1.0f), // not valid
&XMFLOAT3(1.0f, 0.0f, 0.0f), // not valid
&XMFLOAT3(0.0f, 1.0f, 0.0f) // not valid
);
I suggest that you turn up the warning levels on your compiler settings, and enable as much standard conformance as possible. Things get much easier when your compiler tells you what you're doing wrong.
As a solution, you could try simply passing the objects by value:
_pInstanceObject->StartUp(_position,
_rotation,
XMFLOAT3(_scale, _scale, _scale),
XMFLOAT3(0.0f, 0.0f, 1.0f),
XMFLOAT3(1.0f, 0.0f, 0.0f),
XMFLOAT3(0.0f, 1.0f, 0.0f)
);
bool StartUp(XMFLOAT3 _position, XMFLOAT3 _rotation, XMFLOAT3 _scale,
XMFLOAT3 _lookAxis, XMFLOAT3 _strafeAxis, XMFLOAT3 _upAxis);
It looks like your XMFLOAT3 structures are being allocated on the stack, not on the heap. They would get cleaned up when their variables go out of scope.
Try allocating your structures on the heap instead:
XMFLOAT3* _position = new XMFLOAT3;
Related
This is the line which causes the error
vector<transform>::iterator transformIter;
for (transformIter = (*objIter)->transforms.begin(); transformIter != (*objIter)->transforms.end(); objIter++) {
handleTransform((*transformIter));
}
It occurs on the second iteration of the loop regardless of how many transofrms are in the vector.
The obj struct looks like this:
struct obj {
vector<glm::vec4> vertices;
vector<int> elements;
vector<object> objects;
vector<transform> transforms;
};
and the function handleTransform is:
void handleTransform(transform currentTransform) {
if (currentTransform.type == 'r') {
glRotatef(currentTransform.coordinates.x, 1.0f, 0.0f, 0.0f);
glRotatef(currentTransform.coordinates.y, 0.0f, 1.0f, 0.0f);
glRotatef(currentTransform.coordinates.z, 0.0f, 0.0f, 1.0f);
}
if (currentTransform.type == 's') {
glScalef(currentTransform.coordinates.x, currentTransform.coordinates.y, currentTransform.coordinates.z);
}
if (currentTransform.type == 't') {
glTranslatef(currentTransform.coordinates.x, currentTransform.coordinates.y, currentTransform.coordinates.z);
}
}
Iterating through the other vectors in an obj doesn't cause any vector issues, so I have to imagine it's something to do with the handleTransform function, but I can't figure it out.
Replace objIter++ by ++transformIter.
You are erroneously incrementing objIter, not transformIter:
for (transformIter = (*objIter)->transforms.begin();
transformIter != (*objIter)->transforms.end();
objIter++) // ??
It should be:
for (transformIter = (*objIter)->transforms.begin();
transformIter != (*objIter)->transforms.end();
++transformIter)
To avoid mistakes like this, use std::for_each, or if using C++ 11, a ranged-based for loop:
http://en.cppreference.com/w/cpp/language/range-for
With either of these options, you eliminate the need to declare iterators, make mistakes iterating to the next item, or if not those issues, perform a post-increment instead of a faster pre-increment of the iterator (as your original code is doing).
In my program I have a vector containing D3DXVECTOR3 variables. As might be inferred the vector is to contain multiple D3DXVECTOR3 vectors. However for efficiency's sake I only have a single D3DXVECTOR3 variable whose values of x,y and z I change before pushing back into the vector container multiple times and I was just wondering whether its possible to have a single D3DXVECTOR3 variable which you update multiple times before pushing back into your vector container OR do you have to declare a new D3DXVECTOR3 variable for however many vectors you want the parent vector to contain?
Currently the code looks like this:
vector<D3DXVECTOR3> gradients;
D3DXVECTOR3 singleGrad;
singleGrad.x = 1.0;
singleGrad.y = 1.0;
singleGrad.z = 0.0;
gradients.push_back(singleGrad);
singleGrad.x = -1.0;
gradients.push_back(singleGrad);
singleGrad.x = 1.0;
singleGrad.y = -1.0;
gradients.push_back(singleGrad);
singleGrad.x = -1.0;
singleGrad.y = -1.0;
singleGrad.z = 0.0;
gradients.push_back(singleGrad);
Your conception of efficiency is completely wrong when you consider you do not even reserve memory in your vector and then have potential underlying resize with copy of the previous values.
You should consider writing code easy to read and optimize where it will really matters :
std::vector<D3DXVECTOR3> gradients;
gradients.reserve(4);
gradients.push_back({ 1.f, 1.f, 0.f});
gradients.push_back({-1.f, 1.f, 0.f});
gradients.push_back({ 1.f,-1.f, 0.f});
gradients.push_back({-1.f,-1.f, 0.f});
If you are concern with code size, factorize with loop.
std::vector<D3DXVECTOR3> gradients;
gradients.reserve(4);
float const signs[] { 1.f, -1.f };
for( int v{};v!=2;++v )
for( int u{};u!=2;++u )
gradients.push_back({signs[u],signs[v], 0.f});
I'm putting together a pinball table, and here I have a PinballTable class. I want to hold all of the game objects (pinball, bumpers, flippers, etc) in a vector, which I call _gameObjs.
When I iterate through the vector, its returning the last GameObj declared in the constructor, whether that GameObj is in the vector or not. If I add multiple GameObjs to the vector, it will return that last declared GameObj that many times. I'm transitioning from C# and collections seem to be getting the best of me, I'm totally stumped here though
Here, I'm added three objects: two bumpers and one pinball. In the update function, I'm trying to get it to output output the x size of each object just so I know it's iterating correctly. Here, for example, I haven't even added the pinball to the vector, but it's outputting the pinball's x size twice per update call.
#include "PinballTable.h"
GameObj* _pinball;
int TABLE_WIDTH;
int TABLE_HEIGHT;
float _tableTiltedAngle = 6.5f;
float _radiansPerDegree = PI / 180;
float _gravityForce = cos( _tableTiltedAngle * _radiansPerDegree ) * GRAVITY;
vector<GameObj> _gameObjs;
PinballTable::PinballTable( const int width, const int height )
{
TABLE_WIDTH = width;
TABLE_HEIGHT = height;
GameObj bumper1(
GameObj::shapeCircle,
GameObj::typeStatic,
color4f( 1.0f, 1.0f, 0.0f, 1.0f),
point2f( 300.0f, 600.0f ),
vec2f( 40.0f, 0.0f )
);
_gameObjs.push_back( bumper1 );
GameObj bumper2(
GameObj::shapeCircle,
GameObj::typeStatic,
color4f( 1.0f, 1.0f, 0.0f, 1.0f),
point2f( 50.0f, 200.0f ),
vec2f( 50.0f, 0.0f )
);
_gameObjs.push_back( bumper2 );
GameObj pinball(
GameObj::shapeCircle,
GameObj::typeDynamic,
color4f( 1.0f, 1.0f, 0.0f, 1.0f),
point2f( 100.0f, 100.0f),
vec2f( 20.0f, 20.0f)
);
_pinball = &pinball;
}
PinballTable::~PinballTable(void)
{
}
// ------------------------------ Update Functions ------------------------------
void PinballTable::update( GameTime& gameTimer )
{
for( vector<GameObj>::iterator i = _gameObjs.begin(); i != _gameObjs.end(); ++i )
{
cout << i->getSize()->x << endl;
}
}
thanks for the help
get size function just returns a vector2 (x, y components) from a GameObj. The output size matches up with the last declared GameObj size in the PinballTable constructor every time
vec2f* GameObj::getSize( void )
{
return &_size;
}
Solved:
One of the problems, as pointed out by a few, was that the GameObjs are created inside the constructor.
In the GameObj class I was not declaring the different members in the header file. Switching these members to the header file seemed to fix this, for what reason I do not know.
You created 3 GameObj inside the constructor which are going to be destructed after the constructor returns and when you add them to the vector, they are garbage.
Is your GameObj an interface or abstract class? If so, you should not put it directly into a vector, but a pointer to it. Think of a vector as a byte-array containing of serialized copies of what you put into it (since you are coming from C# this should help). C++ does not have a uniform object representation, so it is crucial to keep in mind what space your objects require.
Is this you want,
for( vector<GameObj>::iterator i = _gameObjs.begin(); i != _gameObjs.end(); ++i )
{
cout << (*i).getSize()->x << endl;
}
You need to get the object stored in the vector by the dereference(*) operator.
If at all possible, I'd use a range-based for loop:
for (auto const &g : _gameObjs)
cout << g.getSize()->x << "\n";
This was added in C++11, so you may have to give your compiler a switch to tell it to recognize/allow C++11 constructs (e.g., you normally have to with g++).
The way that you describe your problem, it sounds as if _size is a global variable, and not a member of GameObj
I am trying to pass a pointer to an array of Vertex Data, (base class member) into a method used to initialize the Direct3D Vertex Buffer, (ID3D11Buffer).
I want to use the variable, "v4", the pointer to the array, but I think I am not dereferencing the pointer correctly. Could someone point me in the right direction?
I have tried many ways to make this assignment, but I can only get a basic array work, (sometimes I end up with casting to "const void *" errors).
How would I use a pointer?
The line I am having issue with is ...
vertexSubResourceData.pSysMem = v1;
(p.s. Using the V.S. C++ Nov 2012 CTP compiler .. not released yet ..)
*Answered: Have confirmed that it is a Visual Studio 2012 C++ Nov. CTP Compiler Bug. Arrays of Vector structures declared, even outside of the class, using C++ 11 initialization syntax are being interpreted incorrectly, (unless of course I am using the incorrect array initialization syntax). Also Note: This only pertains to initialization lists associated with pointers. *
Thanks!
// Simplified Code
void Triangle::InitializeVertexBuffer()
{
struct V
{
float X, Y, Z; // vertex position
};
// Compiles But doesn't work as desired.
// changed from V* v4 = new V[] // Compiled without range.
// Pointer to this data would ideally come from base static pointer, or file.
V* v4 = new V[3]
{
{ 0.50f, 0.5f, 0.0f },
{ 0.50f, -0.5f, 0.0f },
{ -0.50f, -0.5f, 0.0f },
};
// Compiles and Works to prove compiler issue with initialization lists.
V* vectorList = new V[3];
vectorList[0].X = 0.5f;
vectorList[0].Y = 0.5f;
vectorList[0].Z = 0.00f;
vectorList[1].X = 0.5f;
vectorList[1].Y = -0.5f;
vectorList[1].Z = 0.00f;
vectorList[2].X = -0.5f;
vectorList[2].Y = -0.5f;
vectorList[2].Z = 0.00f;
unsigned int size = sizeof(V) * 3; //sizeof(* Model::Vertices);
// The Description of the Vertex Buffer
D3D11_BUFFER_DESC vertexBufferDescription = {0};
vertexBufferDescription.ByteWidth = size;
vertexBufferDescription.BindFlags = D3D11_BIND_VERTEX_BUFFER;
// Model Data to be transferred to GPU Buffer.
D3D11_SUBRESOURCE_DATA vertexSubResourceData = {0};
vertexSubResourceData.SysMemPitch = 0;
vertexSubResourceData.SysMemSlicePitch = 0;
// Can't figure out how to dereference v4
vertexSubResourceData.pSysMem = vectorList; // works, but using "v4" doesn't.
// vertexSubResourceData.pSysMem = Model::Vertices;
// This is what I /really/ want .. Pointer to vertice array data from base class
NS::DeviceManager::Device->CreateBuffer(
&vertexBufferDescription,
&vertexSubResourceData,
&NS::ModelRenderer::VertexBuffer);
}
When you write V* v4 = new V[]{...}; it is illegal C++. The CTP compiler is accepting malformed code. Try V* v4 = new V[3]{...};
Checking the C++ standard, from 5.3.4p1:
[ expression ] attribute-specifier-seqopt
So, it looks like an expression is required in the []. I believe new V[] is an extension for compilers (still checking into this).
And as ildjarn points out, you want vertexSubResourceData.pSysMem = v4; as &4 would you give you the address of the pointer, not the array.
Update
I think this is a bug in the compiler. Try the old C++03 syntax: V* v4 = new V[3]; v4[0] = ...; and if that works, then it definitely is a bug.
what's wrong with this syntax? sorry for the newbie question.
source:
Level::Level()
{
NintyDegreeDirections[4] =
{
1.0f, 1.4f, 2.4f, 0.1f
}
...rest of class
header:
//all necessary includes
class Level
{
private:
float NintyDegreeDirections[4];
...rest of header
how do I have an array as a instance member? I'm converting from C#
In the current version of C++ (C++11), you can initialize the member array like this:
Level::Level()
: NintyDegreeDirections( { 1.0f, 1.4f, 2.4f, 0.1f } )
{
}
C++11 isn't universally supported and if you don't have support for this in your compiler you will have to assign to each member in turn.
E.g.:
NintyDegreeDirections[0] = 1.0f;
NintyDegreeDirections[1] = 1.4f;
//...
Did you try:
NintyDegreeDirections[0] = 1.0f;
NintyDegreeDirections[1] = 1.4f;
/* ... */