9
votes
\$\begingroup\$

I have a function that accepts a big amount of data as a parameter (sometimes 1 megabyte) I was thinking which would be the fastest way to pass that data, dunno if I got this right, but here is what I think (functionality doesn't matter, all are the same in my app, since data is never used again after this function).

// slow since the data must be copied to another location 
// in memory and passed to myfunction
function myfunction(data: string): boolean;   

// faster since a pointer to the original data is passed to 
// the function and data is never copied
function myfunction(var data: string): boolean;   

// no idea ??!!!
function myfunction(const data: string): boolean;  
\$\endgroup\$
1

3 Answers 3

12
votes
\$\begingroup\$

Executive summary

Passing by const is the fastest for Delphi string types.

Details

function myfunction(data: string): boolean;

Slow since the data must be copied to another location in memory and passed to myfunction

That's not what happens. In fact the caller does nothing more than pass the string variable, stored as a pointer, to the function. What happens in myfunction is that the reference count to the string is incremented on entry and decremented on exit. This requires an implicit try/finally to be written into the code to ensure that the decrement happens in case of exceptions. The reference counting code and the try/finally consume time.

Note that the string contents are not copied at all because Delphi strings are optimised to use copy-on-write. You only pay the price of copying them if you modify the string.

function myfunction(var data: string): boolean;

Faster since a pointer to the original data is passed to the function and data is never copied

This is pretty much equivalent to the previous by value code above. The parameter (i.e. the pointer to the string) is passed by reference rather than value, but otherwise there are no differences.

function myfunction(const data: string): boolean;

And now we come to the winner. Since the function is not allowed to modify the contents of the string, the compiler can omit the reference counting code and the try/finally. So this is the fastest of all.

\$\endgroup\$
0
1
vote
\$\begingroup\$

If code in myfunction don't modify string, then, surprisingly, all three variants are pretty equal. Strings in Delphi use "copy-on-write semantics" (see last paragraph of AnsiString in help), so they aren't copied until you change them.

From the other hand, "var" and "const" will have same speed. Quote from help: Constant parameters are similar to value parameters, except that you can't assign a value to a constant parameter within the body of a procedure or function, nor can you pass one as a var parameter to another routine.

So, taking into account string handling specifics, first variant, without any modifier, will behave pretty equal to others - string will be passed as pointer, and will be copied only when your code will actually write to it.

Anyway, to be 100% sure, I suggest you write some profiling test. It is quite easy with use of Diagnostics.TStopwatch.

\$\endgroup\$
0
votes
\$\begingroup\$

This appears similar to StackOverflow question 1951192. If you have a real performance need, then try the suggestion there of using FastMM4. You are right that pass-by-reference should blow away pass-by-value for speed on large strings (or large any-kind-of-data).

It could also be worth benchmarking (var data:string) vs. (const data:string) in case the compiler optimizes once better than the other. If they're the same, use const if your function doesn't need to alter the contents of string.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.