Home > Net >  Why does my vector store a copy of my object, and not the original value, in c ?
Why does my vector store a copy of my object, and not the original value, in c ?

Time:01-06

I have a mid-term assignment in which we conduct 3 sets of unit tests with documentation etc for a program from our course. The program I chose is a physics simulation.

Within this program, there are two classes, Thing and World. I am able to independently create these objects. I tried adding the Thing object to the World object by creating a std::vector<Thing> things, and then creating a function to add the Thing to the vector of things. However, when I do that, it seems as though the World object creates its own copy of the Thing, because when I change the Things position, the version of the Thing in the things vector remains the same.

Please provide some guidance on the matter, I feel my problem might be with how I use pointers in this situation.

 void testBoundaryBounce()
 {
      //Create the world
      World world{10.0f, 10.0f, 1.0f};
      //Thing, 2 units away from boundary
      Thing thing{8.0f, 5.0f, 1.0f};
      //Add thing to world (adding it the the things vector)
      world.addThing(&thing);
      //Apply force that should trigger bounce back to x = 7
      thing.applyForce(1.0f, 0.0f);
      //Updating thing so that movement takes effect
      thing.update();
      //Running world update to account for collisions, bounces etc
      world.update();

      std::cout << "thing x : " << thing.getX() << std::endl;

      CPPUNIT_ASSERT(thing.getX() == 7);
 }


Thing::Thing(float x, float y, float radius)
: x{x}, y{y}, dX{0}, dY{0}, radius{radius}
{

}


World::World(float width, float height, float gravity)
: width{width}, height{height}, gravity{gravity}
{
    std::vector<Thing> things;
}



void World::addThing(Thing* thing)
{
    float thingX = thing->getX();
    float thingY = thing->getY();
    float thingRad = thing->getRad();

    std::cout << "Radius : " << thingRad << std::endl;

    if (thingX   thingRad > width || thingX - thingRad <= 0 || thingY   thingRad > 
    height|| thingY - thingRad <= 0)
    {
        std::cout << "Thing is out of bounds or is too large" << std::endl;
    }
    else {
        std::cout << "Thing is good" << std::endl;
        things.push_back(*thing);
    }
}

void World::update()
{
    for (Thing& thing : things)
    {
        thing.update();
        float thingX = thing.getX();
        float thingY = thing.getY();
        float thingRad = thing.getRad();
        float worldGrav = this->gravity;

        std::cout << "thing x: " << thingX << std::endl;
        std::cout << "thing rad: " << thingRad << std::endl;

        //World Boundary Bounces
        if (thingX   thingRad >= width)
        {
            std::cout << "Bounce left" << std::endl;
            thing.applyForce(-2.0f, 0.0f);
            thing.update();
        }
        if (thingX   thingRad <= 0)
        {
            thing.applyForce(2.0f, 0.0f);
            thing.update();
            std::cout << "Bounce right" << std::endl;
        }
        if (thingY   thingRad >= height)
        {
            thing.applyForce(0.0f, -2.0f);
            thing.update();
            std::cout << "Bounce up" << std::endl;
        }
        if (thingY - thingRad <= 0)
        {
            thing.applyForce(0.0f, 2.0f);
            thing.update();
            std::cout << "Bounce down" << std::endl;
        }
        //Thing Collision Bounces
        for (Thing& otherthing : things)
        {
            float thing2X = otherthing.getX();
            float thing2Y = otherthing.getY();
            float thing2Rad = otherthing.getRad();
            if (thingX   thingRad == thing2X   thing2Rad && thingY   thingRad == 
                thing2Y   thing2Rad)
            {
                thing.applyForce(-2.0f, -2.0f);
                thing.update();
                otherthing.applyForce(2.0f, 2.0f);
                otherthing.update();
            }
        }
        //Gravitational Pull
        thing.applyForce(0.0f, worldGrav);
    }
}

CodePudding user response:

Its right in the definition of void push_back (const value_type& val);...

Adds a new element at the end of the vector, after its current last element. The content of val is copied (or moved) to the new element.

so when you call things.push_back(*thing);, you are adding a new element to the 'things' vector which is a copy of the value pointed to by the thing pointer.

You want to change your vector to hold pointers to Thing types instead:

std::vector<Thing *> things;

and add the pointers instead of copies:

things.push_back(thing);

Note you will later have to access fields via -> instead of ., or you can create a reference to it such as:

    for (Thing* pt: things)
    {
        Thing& thing = *pt; 
        thing.update();
        //etc...

CodePudding user response:

Instead of constructing a Thing and copying it into world, you could have World construct the Things that it owns

void testBoundaryBounce()
 {
      //Create the world
      World world{10.0f, 10.0f, 1.0f};
      //Thing, 2 units away from boundary
      Thing * thing = world.addThing(8.0f, 5.0f, 1.0f);
      //Apply force that should trigger bounce back to x = 7
      thing->applyForce(1.0f, 0.0f);
      //Running world update to account for collisions, bounces etc
      //Implies updating all the things
      world.update();

      std::cout << "thing x : " << thing.getX() << std::endl;

      CPPUNIT_ASSERT(thing.getX() == 7);
 }


Thing::Thing(float x, float y, float radius)
: x{x}, y{y}, dX{0}, dY{0}, radius{radius}
{

}


World::World(float width, float height, float gravity)
: width{width}, height{height}, gravity{gravity}
{
    std::vector<Thing> things;
}



Thing * World::addThing(float x, float y, float radius)
{
    std::cout << "Radius : " << radius << std::endl;

    if ((x   radius > width) || (x - radius <= 0) || (y   radius > 
    height) || (y - radius <= 0))
    {
        std::cout << "Thing is out of bounds or is too large" << std::endl;
        return nullptr;
    }
    else 
    {
        std::cout << "Thing is good" << std::endl;
        return &things.emplace_back(x, y, radius);
    }
}

void World::update()
{
    for (Thing& thing : things)
    {
        thing.update();
        float thingX = thing.getX();
        float thingY = thing.getY();
        float thingRad = thing.getRad();
        float worldGrav = this->gravity;

        std::cout << "thing x: " << thingX << std::endl;
        std::cout << "thing rad: " << thingRad << std::endl;

        //World Boundary Bounces
        if (thingX   thingRad >= width)
        {
            std::cout << "Bounce left" << std::endl;
            thing.applyForce(-2.0f, 0.0f);
            thing.update();
        }
        if (thingX   thingRad <= 0)
        {
            thing.applyForce(2.0f, 0.0f);
            thing.update();
            std::cout << "Bounce right" << std::endl;
        }
        if (thingY   thingRad >= height)
        {
            thing.applyForce(0.0f, -2.0f);
            thing.update();
            std::cout << "Bounce up" << std::endl;
        }
        if (thingY - thingRad <= 0)
        {
            thing.applyForce(0.0f, 2.0f);
            thing.update();
            std::cout << "Bounce down" << std::endl;
        }
        //Thing Collision Bounces
        for (Thing& otherthing : things)
        {
            float thing2X = otherthing.getX();
            float thing2Y = otherthing.getY();
            float thing2Rad = otherthing.getRad();
            if (thingX   thingRad == thing2X   thing2Rad && thingY   thingRad == 
                thing2Y   thing2Rad)
            {
                thing.applyForce(-2.0f, -2.0f);
                thing.update();
                otherthing.applyForce(2.0f, 2.0f);
                otherthing.update();
            }
        }
        //Gravitational Pull
        thing.applyForce(0.0f, worldGrav);
    }
}

As an aside, everything bounces off of itself every update

  •  Tags:  
  • Related