Sign in to follow this  
black_darkness

I have two functions that do the same thing. Which one is faster?

Recommended Posts

I want to make my program run faster. I know pointers are quick but does using pointers in this following example increase or decrease speed?

If this is faster I plan on doing something similar with all my functions to increase the speed of my program.

 

Example 1. This is the first function returning type Entity.

 

This is the call.

[CODE]

*hero = hero->hero_turning(*hero,'d',mv);
[/CODE]

 

This is the function

 

[CODE]

Entity Entity::hero_turning(Entity hero, char facing1, vector<Tile> mv) {
 
if (hero.is_swing_hoe == false) {
 
if(hero.facing != facing1) {
hero.facing = facing1;
hero.wait_time = 0;
}
 
else if (hero.can_pass(hero.facing,mv,hero)&& hero.wait_time > 3) {
hero.frame = 1;
hero.move_animation = true;
}
}
return hero;
}
[/CODE]

 

 

Example 2. This one uses pointers and the function is void and doesn't return anything.

 

This is the call.

[CODE]hero->hero_turning(hero,'u',mv);[/CODE]

 

This is the function

[CODE]void Entity::hero_turning(Entity * hero, char facing1, vector<Tile> mv) {

    if (hero->is_swing_hoe == false) {
                    
        if(hero->facing != facing1) {
            hero->facing = facing1;
            hero->wait_time = 0;
        }

        else if (hero->can_pass(hero->facing,mv,*hero)&& hero->wait_time > 3) {
            hero->frame = 1;
            hero->move_animation = true;
        }
    }
}[/CODE]

Share this post


Link to post
Share on other sites
Blindly making micro optimisations is not the solution. However, as you are modifying hero it doesn't make sense to pass by value then return the result a la function 1. This is less about "changing things because you want your program to run faster" and more about choosing the right tool for the right job in the first place. But back to my original point, if you are achieving sub-optimal framerates then there are almost certainly bigger fish to fry that will deliver real, tangible performance benefits. Profile first, identify bottlenecks THEN optimise.

Share this post


Link to post
Share on other sites

There is a reason why second method (using pointers) is faster than the first one.

Processor doesn't have to calculate the memory offset of each member of the structure when using pointers which makes things run faster.

From personal experience, generally everyone knows why pointers are fast, but few people understand why.

But, like GeneralQuery mentioned above, optimisation is bound by many more factors and world peace is a myth.

However, for the question at hand, go ahead and use the second one.

Share this post


Link to post
Share on other sites
I don't really get why you feel like you have to pass in Entity hero at all.
Smells like a design problem, my guess is that your "Entity" class tries to do way too much. (SRP violation)

That said, option one has a lot of potential problems, also problems that is not performance related, so its often not a good idea.
You certainly should not pass the vector<Tile> by value, but as a reference as mentioned.

Ignoring the design problems, in this case I would use a const Entity& for the parameter.
const references are your friend.

Edit: fixed bad formatting by broken post editor Edited by Olof Hedman

Share this post


Link to post
Share on other sites

[quote name='ifthen' timestamp='1357125503' post='5016644']
Please read a book about C++. You are calling a METHOD (as opposed to function). A method belongs to an object. Therefore, you can access a pointer to object you are calling your method from using keyword 'this'. So you can write
[/quote]

 

I did read a book but I started getting confused so I started making this game so I could get some experience in order to understand the book better. This was a really helpful post thank you.

Share this post


Link to post
Share on other sites

Please read a book about C++. You are calling a METHOD (as opposed to function). A method belongs to an object. Therefore, you can access a pointer to object you are calling your method from using keyword 'this'. So you can write

void Entity::turning(char facing1, vector<Tile> mv) {
    if (this->is_swing_hoe == false) {
                            if(this->facing != facing1) {
            this->facing = facing1;            this->wait_time = 0;
        }
        else if (this->can_pass(this->facing,mv,this)&& this->wait_time > 3) {
            this->frame = 1;            this->move_animation = true;
        }
    }
}
and 'this' will correspond to 'hero' if you call it like
hero->turning('d',mv);
Even better, you can remove all the 'this->' from above code. Your compiler knows that in methods, if you write a name of a variable you declared in the class of the object, that is the variable to use (if you didn't write a conflicting declaration in the method, of course).

You also should not pass a std::vector variable by value (that means, not using a pointer or, preferably, a reference). Why? Because your program needs to make a new copy of that vector. That means it must manually copy all the objects (in your case, tiles) your std::vector stores.
In fact, if you think about it, what should the Entity know? It should know on which map it is and its position. If you implement the Map class (which should probably have a vector of tiles), you can use something like
void Entity::turning(char facing1) {        
//not sure what THIS code does, but it is yours, so I won't modify it (except showing the 'OOP way')
    if (is_swing_hoe == false) {
        if(facing != facing1) {
            facing = facing1;
            wait_time = 0;
        }
        //suppose that map can extract all the needed information from the entity using getters
         else if (map->can_pass(this, facing1)&& wait_time > 3) {
            frame = 1;
            move_animation = true;
        }
    }
}
Voila! The function is much more readable. As a rule of thumb, you should always think twice before starting working on a new feature. How will I represent it? Who (which class) will use it? How should I implement it? If you ask and answer all the questions that come to your mind, you will find yourself writing much cleaner (and bug-free) code.

 

 

Okay another question. I am implementing your suggestions but I have a problem. I do not know if it would be efficient for me to include the data type Map as a variable in Entity.

Share this post


Link to post
Share on other sites

Please read a book about C++. You are calling a METHOD (as opposed to function). A method belongs to an object. Therefore, you can access a pointer to object you are calling your method from using keyword 'this'. So you can write

 

 

I did read a book but I started getting confused so I started making this game so I could get some experience in order to understand the book better. This was a really helpful post thank you.

 

If the book got you confused you probably want to write something less complex than a game ;) If its a decent intro book it should have exercises you can work with.. The book will give you answers to all these questions and a lot more and you will understand it on a much better level.

Share this post


Link to post
Share on other sites
I do not know if it would be efficient for me to include the data type Map as a variable in Entity.
If you mean std::map, then it is most probably not efficient to use it as a copy, and a reference ('&') is more effective.

Either use "const std::map<T1,T2> &arg" if you only want to use it to look up values, or use "std::map<T1,T2> &arg" if you need to change the map.

If this map is part of the Entity class, then you should define it as a member of the Entity class instead, and you will have immediate access to it that way (no need to access it as an argument).

A word about efficiency: the standard procedure is to first make the general design, then benchmark to find the bottlenecks, and last thing to optimize. Otherwise, there is a high risk that you spend effort on optimizing things that have no real effect on the application, or even worse, create bad design. Edited by larspensjo

Share this post


Link to post
Share on other sites
There is a reason why second method (using pointers) is faster than the first one.
Processor doesn't have to calculate the memory offset of each member of the structure when using pointers which makes things run faster.
From personal experience, generally everyone knows why pointers are fast, but few people understand why.

 

Late to the party, but no, that is not why pointers are faster.

 

The pointer version of the function is faster only because it accesses and modifies the initial object in place, whereas the non-pointer version copies the entire object twice (once when passed as a parameter by-value, and once when returned by-value).

Share this post


Link to post
Share on other sites
There is a reason why second method (using pointers) is faster than the first one.
Processor doesn't have to calculate the memory offset of each member of the structure when using pointers which makes things run faster.
From personal experience, generally everyone knows why pointers are fast, but few people understand why.

 

Late to the party, but no, that is not why pointers are faster.

 

The pointer version of the function is faster only because it accesses and modifies the initial object in place, whereas the non-pointer version copies the entire object twice (once when passed as a parameter by-value, and once when returned by-value).

 

That's just another reason, and not the only reason. Two people can still be right with different facts sir, doesn't mean one needs to diss the other. cool.png

Share this post


Link to post
Share on other sites

Even though what you're saying is highly debatable (and trust me, I have tried fiddling with pointers way too much over all these years) lets just leave it at that.

I have absolutely no intention of entering this debate, following in the footsteps of many of our esteemed predecessors.

To each his own. cheers.

Share this post


Link to post
Share on other sites
Okay another question. I am implementing your suggestions but I have a problem. I do not know if it would be efficient for me to include the data type Map as a variable in Entity.
The best way is to use a reference (it doesn't copy the data of object, but you use it in same way as an object, unlike a pointer). Making a reference a class member is a bit tricky (requires initializer lists), but this code does it:
//file Entity.h
#pragma once
//forward declaration of a map
//in C++, you can declare a class many times,
//but define it only once!
class Map;
class Entity {
  public:
    //you have to make a constructor with an initialization list
    //because the reference, unlike a pointer, must be defined at its initialization
     Entity(Map & _map) : map(_map) {
      //your constructor, blah blah blah
    }
    //note you can also use Entity(Map & map) : map(map) {...}, it has the same effect
    //(refer to footnote 1)
    void foo();
    protected:
      Map & map;
};

//file Map.h
#pragma once
#include "Entity.h"
class Map {
  void bar();
  //you can pass the current object as a parameter to a function using this
  Entity thisMapEntity() {
    return Entity(this);
  }
};

//file Entity.cpp
#include "Entity.h"
#include "Map.h"
Entity::foo() {
  //note you couldn't define foo in Entity.h,
  //because class Map wasn't defined yet,
  //just declared 

  //calls the entity's map's function "bar"
  map.bar();
}
Footnote 1 Edited by ifthen

Share this post


Link to post
Share on other sites
Okay another question. I am implementing your suggestions but I have a problem. I do not know if it would be efficient for me to include the data type Map as a variable in Entity.
The best way is to use a reference (it doesn't copy the data of object, but you use it in same way as an object, unlike a pointer). Making a reference a class member is a bit tricky (requires initializer lists), but this code does it:
//file Entity.h
#pragma once
//forward declaration of a map
//in C++, you can declare a class many times,
//but define it only once!
class Map;
class Entity {
  public:
    //you have to make a constructor with an initialization list
    //because the reference, unlike a pointer, must be defined at its initialization
     Entity(Map & _map) : map(_map) {
      //your constructor, blah blah blah
    }
    //note you can also use Entity(Map & map) : map(map) {...}, it has the same effect
    //(refer to footnote 1)
    void foo();
    protected:
      Map & map;
};

//file Map.h
#pragma once
#include "Entity.h"
class Map {
  void bar();
  //you can pass the current object as a parameter to a function using this
  Entity thisMapEntity() {
    return Entity(this);
  }
};

//file Entity.cpp
#include "Entity.h"
#include "Map.h"
Entity::foo() {
  //note you couldn't define foo in Entity.h,
  //because class Map wasn't defined yet,
  //just declared 

  //calls the entity's map's function "bar"
  map.bar();
}
Footnote 1

Thank you. This is good stuff.

Share this post


Link to post
Share on other sites

[quote name='swiftcoder' timestamp='1357148992' post='5016771']
Accessing a member variable in a structure requires the calculation of an offset, regardless of whether you are accessing the structure directly, or via a pointer to its location. And in both cases, this calculation will almost always be done ahead of time by the compiler, and evaluate to a simple add/offset operation at runtime.
[/quote]

 

In case of global parameters allocated by the linker, it should be possible to access member variables without using an offset operation at runtime. At least that is the way it was done in the C compiler I made at around 1984 for the NS32016, with a reservation for corrupt (wetware) memory.

 

When accessing members of structures allocated on the stack, however, a runtime offset operation should always be needed, to the FP or SP. So I suppose that is the normal case.

Share this post


Link to post
Share on other sites
While the philosopher in me applauds your application of the Heisenberg uncertainty principle, you are however blatantly incorrect in this instance.
And the LOL of the day award goes tooooooooooooooo....

Also, I recall from reading the 80386 manual that member offset access is optimized by use of a different addressing method in the hardware. Adding that to the cache I'd imagine that in the majority of cases the value (or call address) is already on hand when required. Edited by Khatharr

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this