Variable resetting problem in a list of objects - c++

Today I was writing some SDL C++ program, with squares called particles. My problem is that, for some reason, variable y in instances of class Particle is always resetting to the value passed into the constructor after incrementing it by 1. I'm storing the objects in a list.
That's a method that's called every frame:
void everyFrame(){
this->y+=1;
std::cout<<"update y: "<<this->y<<std::endl;
}
And this method is also called every frame, after the everyFrame() method:
void blit(){
this->rect.x=this->x*10;
this->rect.y=this->y*10;
std::cout<<"blitting y: "<<this->y<<std::endl;
SDL_BlitSurface(this->image,NULL,screen,&this->rect);
}
This is the part of the code, where I'm adding an object/objects to the list:
std::list<Particle> particles;
particles.push_back(Particle(2,10,5));
And there I'm executing these 2 methods in the main loop:
for(Particle x:particles){
x.everyFrame();
}
for(Particle x:particles){
x.blit();
}
The console output of the program when y 5 is passed into the constructor is just:
update y: 6
blitting y: 5
looped around.
I also found out that when I'm storing an object in a normal variable, not in a list, then it works. Is there any reason/fix for it not working in a list?

These lines:
for(Particle x:particles){
x.everyFrame();
}
are not modifying the particles list.
This is because Particle x:particles is creating a copy of each element before calling x.everyFrame().
You need to change it to:
for(Particle & x:particles){ // NOTE: added &
x.everyFrame();
}
Taking a refernce to the list element will modify the element in the list.
The same applied to the second loop applying blit().
A side note:
Using the auto keywoard is usually recomended in this case. You need to keep in mind that auto does not include CV qualifiers, and pointerness/referenceness. Therefore you need:
for(auto & x:particles){ ... }
And if you are traversing a container without modifying the elements, it is rcomended to use:
for(auto const & x:particles){ ... }

Related

Why does push_back give a segmentation error?

About the project:
I am working on an Opengl ray-tracer, which is capable of loading obj files and ray-trace it. My application loads the obj file with assimp and then sends all of the triangle faces (the vertices and the indices) to the fragment shader by using shader storage objects. The basic structure is about to render the results to a quad from the fragment shader.
When I load bigger obj-s (more than 100 triangles), it took so much time for the computer to do the intersections, so I started creating a BVH-tree to speed up the process. My BVH splits up the space into two axis-aligned-bounding-boxes recursively based on the average median of the triangles faces contained in the AABB.
I succeed to build the BVH tree structure (on CPU) and now I want to convert it to a simple array, then send it to fragment shader (to a shader storage buffer).
Here is the method responsible for converting the BVH root node into an array:
BvhNode bvhNode; //global variable
BvhNode* putNodeIntoArray() {
int size=bvhNode.getNumberOfNodes();
BvhNode nodesArray[size];
int current_index = 0;
vector<BvhNode> tempNodes;
tempNodes.push_back(bvhNode);
BvhNode current_node;
while (!tempNodes.empty()) {
current_node = tempNodes.at(0);
tempNodes.erase(tempNodes.begin());
nodesArray[current_index] = current_node;
if(!current_node.isLeaf)
{
tempNodes.push_back(current_node.children.at(0)); // Segmentation error occurs here!
tempNodes.push_back(current_node.children.at(1));
}
current_index++;
}
return nodesArray;
}
About the problem:
I don't know why, but it gives me a segmentation error, when I want to push_back the first child to the tempNodes vector (the exact place can be seen by the comment above). It seems to me current_node.children.at(0) does not exist, but actually it exists according to the debugger.
I tried to write reference (&) operator: tempNodes.push_back(&current_node.children.at(0));, but in this case it is giving me weird coordinates to the objects. I tried to define the variables in the function as globals - trying to avoid scope problems -, as well as defining the current_node variable as a pointer. Unfortunately none of them gave me better results.
Here is my BvhNode class, if it helps:
class BvhNode {
public:
BBox bBox;
int depthOfNode;
vector<BvhNode> children;
int order;
bool isLeaf;
bool createdEmpty = false;
vector<glm::vec3> primitiveCoordinates;
BvhNode() {}
BvhNode(BvhNode *pNode) {}
BvhNode(vector<glm::vec3> &primitiveCoordinates) {
this->primitiveCoordinates = primitiveCoordinates; }
void buildTree(vector<glm::vec3>& indicesPerFaces, int depth) {... }
Update 1:
I updated the method according to the comments. So I changed the type of the returning value to vector insted of BvhNode*. The algorithm works fine until it reaches the process of putting the leaf nodes into the std::vector. So when it starts to putting the last level of the graph to the vector, it gives me this error:
Program received signal SIGSEGV, Segmentation fault.
0x00007fbda4d69c01 in __GI___libc_free (mem=0x555be3a9dba0) at malloc.c:3123
3123 malloc.c: No such file or directory.
I managed to put seven nodes (meaning all depth levels of the tree except the level of leaves) into the vector. I also tried to run valgring, but actually valgrind does not give me any error, not like in CLion.
This is my modified method. I commented the place of segmentation fault and the fixes.
BvhNode bvhNode;
vector<BvhNode> putNodeIntoArray() {
int size=bvhNode.getNumberOfNodes();
// FIX: I modified the array into an std::vector
vector<BvhNode> nodesArray(size);
int current_index = 0;
vector<BvhNode> tempNodes;
tempNodes.push_back(bvhNode);
BvhNode current_node;
while (!tempNodes.empty()) {
current_node = tempNodes.front();// Segmentation error!!
tempNodes.erase(tempNodes.begin());
nodesArray.at(current_index)=current_node;
nodesArray.at(current_index).children.clear();
// FIX: I also modified this not to iterate through leaves' children, because they don't exist.
if(!current_node.children.empty())
{
tempNodes.push_back(current_node.children.at(0));
tempNodes.push_back(current_node.children.at(1));
}
current_index++;
}
return nodesArray;
}
Your vectors store the BvhNodes everywhere by value.
This means that every time you push_back a node, its copy constructor is called, which in turn copies the children vector member inside the node, which copies its own elements etc.
This basically results in complete subtrees being copied/freed every time you insert or erase a node.
This in turn can result in memory fragmentation, which can eventually cause a vector reallocation to fail and cause a segfault.
Without the full code, I can recommend these 2 things:
Store the children as (smart) pointers instead of by value
Create a custom allocator for the vectors to enable a more fine-grained debugging, and check for allocation failures
Actually the problem was in the creation of the Bvh Tree. Because I wanted to reach the children in the form of 2*i+1 and 2*i+2, I was using a method to make the binary tree full (every level has maximum number of nodes). In this method I had to push empty nodes to the tree.
I was creating the empty node like this:
BvhNode emptyNode;
instead of this:
BvhNode *emptyNode = new BvhNode();
So, when the method finished, the lifetime of the emptyNode was ended. And that caused the segmentation fault.
Moreover, there was also a problem, that I stored the BvhNode by value during the creation of the flat binary tree as Balázs Kovacsis pointed out. This option made the app much slower and it was another potential place to cause segmentation fault.

c++ Box2D moving and rendering Dynamic bodies in a vector

I have created a game which uses a color coded image to create different bodies/fixtures. So for example if the pixel is green it will get stored into an array as 7 and then the program will create a body called enemy. If there are 10 green pixels, 10 enemies will be created:
else if (array[w][h]==7)
{
b2BodyDef Enemy_BodyDef;
Enemy_BodyDef.type = b2_kinematicBody;
Enemy_BodyDef.position.Set(x,y);
m_enemyBody = m_world->CreateBody(&Enemy_BodyDef);
m_enemyBody->SetAngularVelocity(0.0);
m_enemyBody->SetAngularDamping(0.3f);
m_enemyBody->SetLinearDamping(5.0f);
m_enemyBody->SetFixedRotation(true);
b2PolygonShape Enemy_dynamicBox;
Enemy_dynamicBox.SetAsBox(2.5f, 2.5f);
b2FixtureDef Enemy_fixtureDef;
Enemy_fixtureDef.shape = &Enemy_dynamicBox;
Enemy_fixtureDef.density = 1.0f;
Enemy_fixtureDef.friction = 0.1f;
Enemy_fixtureDef.restitution=.0f;
m_enemyFixture=m_enemyBody->CreateFixture(&Enemy_fixtureDef);
enemyBody a;
m_enemybodies.push_back(a);
}
within render:
ngl::ShaderLib *shader9=ngl::ShaderLib::instance();
(*shader9)["nglDiffuseShader"]->use();
for(unsigned int i=0; i<m_enemybodies.size(); ++i)
{
m_enemybodies[i].m_enemy_position.m_x = m_enemyBody->GetPosition().x;
m_enemybodies[i].m_enemy_position.m_y = m_enemyBody->GetPosition().y;
m_enemybodies[i].m_enemy_dimention.set(5.0f,5.0f);
m_transform.reset();
{
shader9->setShaderParam4f("Colour",1.0f,0.0f,0.0f,1.0f);
m_transform.setScale(m_enemybodies[i].m_enemy_dimention.m_x,m_enemybodies[i].m_enemy_dimention.m_y,0.1);
m_transform.setPosition(m_enemybodies[i].m_enemy_position.m_x,m_enemybodies[i].m_enemy_position.m_y,0.0);
loadMatricesToShader();
prim->draw("cube");
}
}
The b2Fixtures are being placed in the correct location however ONLY the last one is being rendered. this is also true for when I try to set the linear velocity of them, only the last one in the array is moved and rendered.
Using the fact that they are in a Vector, how can I iterate through and get them to render and move?
Edit:
enemyBody a;
m_enemybodies.push_back(a);
this refers to a struct that I created for the placement and rendering of the bodies:
typedef struct
{
ngl::Vec2 m_enemy_position;
ngl::Vec2 m_enemy_dimention;
}enemyBody;
There are two things I see which may cause issues. First, and most importantly, is the apparent use of pointers to local/temporary variables:
b2BodyDef Enemy_BodyDef;
...
m_enemyBody = m_world->CreateBody(&Enemy_BodyDef);
b2PolygonShape Enemy_dynamicBox;
...
Enemy_fixtureDef.shape = &Enemy_dynamicBox;
b2FixtureDef Enemy_fixtureDef;
...
m_enemyFixture=m_enemyBody->CreateFixture(&Enemy_fixtureDef);
After you leave this function/method these local variables no longer exist and any pointers to them are invalid. Trying to access a pointer to these local variables at this point will result in undefined behaviour. If you really need to create multiple objects with references to each other you'll need to use dynamic memory:
b2PolygonShape* pEnemy_dynamicBox = new b2PolygonShape;
Enemy_fixtureDef.shape = Enemy_dynamicBox;
Although you will need to remember to delete allocated memory. A more idiomatic C++ solution would use std::shared_ptr<>.
Another issue may be the last two lines:
enemyBody a;
m_enemybodies.push_back(a);
This seems to just push a new, uninitialized/setup enemy body to the vector. What happened to m_enemyBody that you just setup in the previous lines? Did you mean to do something like:
m_enemybodies.push_back(*m_enemyBody);
instead?
Update
Looking more closely at your rendering loop it is obvious why you're only getting one body being displayed. This code:
m_enemybodies[i].m_enemy_position.m_x = m_enemyBody->GetPosition().x;
m_enemybodies[i].m_enemy_position.m_y = m_enemyBody->GetPosition().y;
m_enemybodies[i].m_enemy_dimention.set(5.0f,5.0f);
simply sets each body in the vector to the same exact coordinates and dimensions. This, along with your confusion of pushing an empty enemyBody into the vector, is the cause of your problems.
To fix it change one line in your creation function(not including the fixes of using temporary variable pointers):
m_enemybodies.push_back(*m_enemyBody);
and in your rendering loop simply do:
for(unsigned int i=0; i<m_enemybodies.size(); ++i)
{
m_transform.reset();
shader9->setShaderParam4f("Colour",1.0f,0.0f,0.0f,1.0f);
m_transform.setScale(m_enemybodies[i].m_enemy_dimention.m_x,m_enemybodies[i].m_enemy_dimention.m_y,0.1);
m_transform.setPosition(m_enemybodies[i].m_enemy_position.m_x,m_enemybodies[i].m_enemy_position.m_y,0.0);
loadMatricesToShader();
prim->draw("cube");
}
Note that if you are using a C++11 compatible compiler this loop can be more simply expressed like:
for (auto & body: m_enemybodies) {
...
m_transform.setScale(body.m_enemy_dimention.m_x, body.m_enemy_dimention.m_y, 0.1);
m_transform.setPosition(body.m_enemy_position.m_x, body.m_enemy_position.m_y, 0.0);
...
}

Combining functors and lambdas

I have a functor that creates a linearly spaced set of values . . .
//Linear spaced generator
struct gen_lin {
float mi, inc;
public:
gen_lin(float _mi=1.f, float _inc=1.f) : mi(_mi), inc(_inc){};
float operator()() {
return mi+=inc;
}
};
And I can fill a vector with values like so ...
const size_t elements = 400;
std::vector<float> x(elements);
std::generate_n(x.begin(), elements, gen_lin(10.f,5.f) );
Now, I can easily convert this to a log scale using a lambda like so ...
auto lin = gen_lin(10.f,5.f);
std::generate_n(x.begin(), elements, [&](){return logf(lin());} );
But when I try to squeeze it all on to one line, the vector is entirely filled with the value of logf(10.)
std::generate_n(x.begin(), elements, [](){return logf( gen_lin(10.f,5.f)() );} );
Why, and is it possible to tweak my last line of code to make it work?
With this, you are creating a single gen_lin object, and using it multiple times:
auto lin = gen_lin(10.f,5.f);
std::generate_n(x.begin(), elements, [&](){return logf(lin());} );
With this, you are creating several gen_lin objects:
std::generate_n(x.begin(), elements, [](){return logf( gen_lin(10.f,5.f)() );} );
Each time you create a new gen_lin object, the current value gets reset.
In the first case:
auto lin = gen_lin(10.f,5.f);
std::generate_n(x.begin(), elements, [&](){return logf(lin());} );
You have a persistent gen_lin object, lin, that gets updated with every call to the lambda. But with your one-liner, you are just creating fresh gen_lin object with every call to the lambda, getting the first value that it returns, and then throwing the object away. Since it's a fresh object, initialized with the same constant values, it's going to give you the same value every time.
Each lamdas call creates a new instance of your functor in the second case.
Stuff like bind might fix your problem. Make the lambda take your functor as an argument and use bind to attach a common instance to that argument?
Or use a compose functor of whatever flavour.

c++ - Creating class instance in function and using it later

Can I do this:
static Toggle GetAutoUpdatedToggle(DWORD key, bool initialState = false)
{
Toggle tempToggle(key, initialState);
autoUpdateToggles.push_back(tempToggle); //This is static member - std::vector<Toggle>
return tempToggle;
}
And I'm also using it later like that:
void Toggle::UpdateAllFromFactory() //This is static function
{
for each (Toggle toggle in autoUpdateToggles)
{
toggle.Update();
}
}
Is this good way of doing it?
UPDATE 1 - After your suggestoins:
static Toggle* GetAutoUpdatedToggle(DWORD key, bool initialState = false)
{
Toggle *pToggle = new Toggle(key, initialState);
m_autoUpdateToggles.push_back(pToggle);
return pToggle;
}
void Toggle::UpdateAllFromFactory()
{
for (std::vector<Toggle*>::iterator it = m_autoUpdateToggles.begin(); it < m_autoUpdateToggles.end(); it++)
{
(*it)->Update();
}
}
No, this is not a good way of doing it, because you pass around copies of Toggle:
GetAutoUpdatedToggle returns a copy of the Toggle that it just pushed into the vector. It's not in itself a wrong thing to do, but any manipulations the caller may do on the returned toggle would not be reflected on the one you pushed onto the vector
The for loop goes through elements of the vector, creating a copy for use inside the loop body. Unless the Toggle itself has a pointer-like semantic, the Update() action would not be reflected on Toggle objects inside the vector.
To fix this issue, make GetAutoUpdatedToggle return a reference to the Toggle object that it just pushed onto the vector, and use a vector<Toggle>::iterator object to iterate through the stored toggles. This would let you operate on the actual objects, rather than on their copies.
Your static function returns a copy of the Toggle. .push_back will also create a copy of the toggle. Thus the Toggle you return is not in the autoUpdateToggles and cannot be updated later.
Toggle myToggle = GetAutoUpdatedToggle(key);
/* ... */
Toggle alternativToggle = myToggle;
// alternativToggle == myToggle is true
Toggle::UpdateAllFromFactory();
// alternativToggle == myToggle is still true
Also note that your current implementation of Toggle::UpdateAllFromFactory(); uses copies of Toggles if you didn't use iterators instead.
You'll have to provide a handle to your Toggle object. This can be a simple pointer or any other object that doesn't loose the identity of the specific Toggle when being copied.

Filling list inside object and accessing to it later

I'm sorry if the title isn't very explicit, but I'll try to explain it better. I'm not very familiar with c++ and I'm using openFrameworks for the first time. I'm trying to do something that's probably quite easy, at least in other languages it is, but I'm not being able to do it :(
I have a class Video and inside it I have an object list<ofImage> keyFrames; and several methods to interact with it like the following:
void addKeyFrame(ofImage img) {
if(keyFrames.size() == 0) {
keyFrames.push_front(img);
}
else {
keyFrames.push_back(img);
}
}
list<ofImage> * getKeyFrames() {
list<ofImage> *list = &keyFrames;
return list;
}
void clearKeyFrames() {
keyFrames.clear();
}
In other class I have several Video objects and I have a function that uses addKeyFrame(ofImage img) to fill the list for each object. In the end of that function if I print the list size it is greater than zero.
Inside draw() function I iterate each Video object and I try to draw each image inside their keyFrame list, but the list is always empty and I just filled it with images... I'm using getKeyFrames() function to return a pointer to the list. How can it be empty if I just added objects to it in another function and if I verified that the size was greater than zero? And if I try to debug the application I feel even more lost lol.
Please tell me if you need anymore information and if you know what I'm doing wrong. Thanks!
Ok, A few little things:
1- You shouldn't check for empty lists (or any other STL containers) like this:
if(keyFrames.size() == 0)
This is faster and more "stylish":
if(keyFrames.empty())
2- You've created an unnecessary variable here:
list<ofImage> * getKeyFrames() {
list<ofImage> *list = &keyFrames;
return list;
}
You could do just:
list<ofImage> * getKeyFrames() {
return &keyFrames;
}
3- Pointers are not (most times) the best solution in C++. A reference is the most used substitute, but it would be even better in htis case if you returned an iterator:
list<ofImage>::iterator GetBeginIterator() {
return keyFrames.begin();
}
This way you could use the iterator just like a pointer, increasing it to iterate trough the frames and dereferencing it (with * operator)...