9

As answered in this question by Charles Bailey pass by constant reference should be considered when the object type is large but what kind of object is considered large?

EDIT: OK for providing more data that could be used to provide a more concrete answer I decided to add a real world problem to this description.

Suppose we have an object like this:

typedef struct dipl {
    quint16 __id;
    quint16 __pos;
    quint16 __len;
} data;

And we have another object like this:

class bidipl
{
public:
    bidipl();
    quint8 id();
    void setid(quint8 __id);
    void appenddipl(dipl __dipl);
private:
    qint8 _M_id;
    dipllist _M_dipllist;
};

Where dipllist is typedef QList<dipl> dipllist;. Objects dipl and bidipl are created once but accessed over maybe 100 times a minute. So how should we pass dipl to our append function?

void appenddipl(dipl __dipl);

Or

void appenddipl(const dipl& __dipl);
Community
  • 1
  • 1
max
  • 2,627
  • 1
  • 24
  • 44
  • 10
    Larger than the processor word size – Charles Salvia Aug 12 '14 at 21:03
  • 1
    Wasn't there a very similar question posted a few minutes ago? – yizzlez Aug 12 '14 at 21:03
  • 2
    What about this strategy: always pass by const ref if you can (i.e. if you don't need to modify the argument). Then you don't need to think about sizes. ;-) Of course, @CharlesSalvia is right: if it's smaller than the processor word size, you don't have to pass by reference. I was thinking about larger things... Not sure what order of magnitude you are asking about. – Oguk Aug 12 '14 at 21:04
  • @awesomeyi yes but due to a lot of down votes another user suggested asking it this way. – max Aug 12 '14 at 21:04
  • @Oguk I prefer to pass integral types by value, but your strategy is essentially what happens anyway when you have template parameters, e.g. `template void foo(const T&);`. – Charles Salvia Aug 12 '14 at 21:05
  • When your handy profiling tool shows such a gain (in speed or memory footprint). Whether the gain is meaningful or not depends on what the code is doing. If this is something that's called once over the lifetime of the program, then it *really* doesn't matter. If it's something that's called hundreds of thousands of times in a tight loop, then it *can* matter. **Measure** (either through a profiling tool or through instrumenting your code manually), don't guess. – John Bode Aug 12 '14 at 21:10
  • I remember some Boost thing that could provide a reasonable argument type. I'm unable to find it now though. :( – Cheers and hth. - Alf Aug 12 '14 at 21:13
  • There's a difference between C and C++. The answers for each language are fairly different. – Kerrek SB Aug 12 '14 at 21:24

4 Answers4

8

There are two separate costs associated with passing objects by value: Copying the data representation, and executing constructors. You need to consider the cost of both.

  • Copying data is generally fast, but keep it within reason. It's OK to pass struct { int[7]; } by value, but probably not so much for struct { int[20000]; }.

  • Executing constructors may perform dynamic allocation, which brings the risk of exceptions and the cost of synchronization. This may be negligible, or it may be important. It depends.

The only variables you should probably pass by value unconditionally are those of word-sized, built-in types. For everything else you should think about the trade-offs.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
5

What should be considered large enough to justify passing by reference instead of by-value? You will find answers varying from:

  • anything that is larger than a natural data type on the processor (32-bits on x86, 64-bits on x86-64): here even std::pair<int, int> should be passed by reference.

to

  • only containers that hold data into dynamic memory location (e.g. vectors, strings)

My personal taste is: primitive data by value, structures by reference.

The only productive answer you will find by profiling the specific application on the specific architecture. Any talk about performance without actual profiling is in vain.

bolov
  • 72,283
  • 15
  • 145
  • 224
  • +1 for the bold text. Actual performance gain will depend on how often it is passed, not on how much faster a single call might be. – Kenny Ostrom Aug 13 '14 at 17:27
3

As Charles said, when the value in question has a size equal to or smaller than the size of a reference to the object, there is an obvious performance gain for just passing the value instead of a reference. However, since accessing the value MAY require a dereference operation, depending on details about the context and how "smart" the compiler is, it could still possibly be "worth it" to pass around a value whose size is slightly larger than a reference. However, that is starting to split hairs and is rarely significant.

Dwayne Towell
  • 8,154
  • 4
  • 36
  • 49
  • 2
    There are certain cases where it's beneficial to pass-by-value objects larger than a reference - a common example is SSE/AVX vectors. AVX allows passing 256 bits in a single registers, which is arguably faster than pass-by-ref. – Drew McGowen Aug 12 '14 at 21:14
  • 1
    +1 for mentioning pass-by-reference may require deference operations. Not everyone knows about that. Especially if your function calls other functions the compiler can't see, it has to recheck the parameter in case it was changed outside. – Neil Kirk Aug 12 '14 at 21:37
-2

Anything that is not a fundamental type, meaning any class object, struct, or container

DetectivePikachu
  • 650
  • 3
  • 14
  • 3
    struct's can be smaller then a pointer, or the processors word size. so this isn't correct. – ideasman42 Aug 13 '14 at 04:21
  • Only if there is nothing in them, which is completely irrelevant because it could be true for class objects as well. It is never going to in practice. – DetectivePikachu Aug 13 '14 at 14:03