0

I am working on a project with a friend that does a lot of computation and we are using c++ for it. I havent used c++ in a while and he is suggesting some fixes. I hoped I could come here for a more in depth explanation and maybe could be linked to some more articles.

He says its more efficient instead of having this

Hand::Hand(Card one, Card two)

To have this

Hand::Hand(const Card &one, const Card &two)

Is this correct? What about passing a constant address rather than the object itself makes it more efficient? He mentioned passing a reference instead of making a copy. If I dont pass by address, will it construct a new card object as a copy of the one I've passed?

Also

Instead of

bool Hand::hasFourKind(Card board[])

Have this

 bool Hand::hasFourKind(const Card *board)

This passes a pointer to the start of the array instead of making an array copy?

k9b
  • 1,457
  • 4
  • 24
  • 54
  • They are not exactly the same things, so depends on the areas of where to use them. – Emz Oct 08 '15 at 22:16
  • *"Is this correct?"* Maybe yes, maybe no. Welcome to C++ optimizing, implement both and measure. The first one makes two copies, but has better locality. May go either way depending on the class and the function. – Baum mit Augen Oct 08 '15 at 22:16
  • 1
    The array would decay to a pointer in any case instead of passing a copy. – πάντα ῥεῖ Oct 08 '15 at 22:17
  • For the first one, it depends on how big `Card` is or whether it allocates resources. For the second, they are identical except for the `const`. – rlbond Oct 08 '15 at 22:19
  • Just an observation, if you are already in the `Hand` class, why do you need to pass in the Cards for the hand in `hasFourKind`? – smac89 Oct 08 '15 at 22:44
  • https://stackoverflow.com/questions/2139224/how-to-pass-objects-to-functions-in-c check this question – EvgeniyZh Oct 08 '15 at 23:24

3 Answers3

0

In most cases, if you don't need a local variable to be modified, the latter method of the first example is faster, because the entire object will not have to be copied on the stack for the function to use it. Instead, a pointer will be pushed onto the stack, which takes less time. (Although some calling conventions allow passing small arguments in registers, which is even faster.)

For small objects, the time spent in copying may not be an issue, but may be more evident for large classes/structs.

The second examples have identical operation (disregarding the constness), since the array would not be passed by value in any case. It would be passed as a simple pointer, or passed "by reference."

owacoder
  • 4,815
  • 20
  • 47
0

From an optimisation point of view, the compiler can not rely on const actually meaning "won't change". const_cast allows a function to alter the const-ness of something, such that it can be altered. It is useful for the programmer to know that "I get an error if I accidentally modify this" (in particular mistyping if (a = b) instead of if (a == b)).

If the source code of a function is available to the compiler, it can itself prove that a value isn't being changed, or is being changed, regardless of whether you mark it const or not.

In a video with Chandler Carruth (one of the currently most active developers of Clang and LLVM), he actually promotes using non-reference calls for any type that is reasonably small. Often, the compiler will optimise away the copy of the argument anyways, because the reference MAY be modified [so if the compiler doesn't have the source code available, it won't know if the value is being changed or not]

Whether you use Card board[] or Card *board will not change things, the compiler will generate exactly the same code either way - if you want others reading the code to understand if the function is expected to modify the value or not, then add const for values that aren't being changed.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
0

This

Hand::Hand(const Card &one, const Card &two)

is more efficient than this

Hand::Hand(Card one, Card two)

For 2 reasons

  1. it avoids making a copy of the Cards
  2. If you wanted to maintain a Deck of cards, it is possibe with the first method but not possible with the second method for reasons explained by my first point

This

bool Hand::hasFourKind(Card board[])

is equivalent to this

bool Hand::hasFourKind(const Card *board)

because they both represent array of cards, but the first one is just syntatic sugar for pointer to cards, so they both actually represent pointer to cards.

The second is better because it implies that the board cannot be modified by anyone else. This is not really much of a guard because of const_cast which can be used to remove the constness of an object. If you really wanted to ensure that the cards cannot be modified by anybody in that method, then I would suggest you change design a bit to enable this:

bool Hand::hasFourKind() const;

Where the cards are part of the Hand class and cannot be modified by anyone

smac89
  • 39,374
  • 15
  • 132
  • 179