Writing Efficient Arguments

S

spekyuman

Pointer and reference arguments provide C++ programmers with the
ability to modify objects. What is more efficient, passing arguments
via pointer or reference? Avoid the stereotypical urge of debating
effective coding style. Instead, think of particular scenarios:
passing a 512MB object to function. Think behind the scenes, from the
stack and heap to the physical linking and build of the program.
 
D

Default User

Pointer and reference arguments provide C++ programmers with the
ability to modify objects. What is more efficient, passing arguments
via pointer or reference? Avoid the stereotypical urge of debating
effective coding style. Instead, think of particular scenarios:
passing a 512MB object to function. Think behind the scenes, from the
stack and heap to the physical linking and build of the program.


No way to tell. It's all platform-specific. If the implementation uses
pointers behind the scenes, there's likely little difference.

If it's important, profile. If not, then use the construct that most
clearly represents the intent of the program.





Brian
 
R

red floyd

Pointer and reference arguments provide C++ programmers with the
ability to modify objects. What is more efficient, passing arguments
via pointer or reference? Avoid the stereotypical urge of debating
effective coding style. Instead, think of particular scenarios:
passing a 512MB object to function. Think behind the scenes, from the
stack and heap to the physical linking and build of the program.

I propose that we ban the word "efficient" from newsgroup posts unless
the poster has benchmarked and shown that the micro-optimization he
wants actually may do something.
 
G

gpuchtel

Pointer and reference arguments provide C++ programmers with the
ability to modify objects. What is more efficient, passing arguments
via pointer or reference? Avoid the stereotypical urge of debating
effective coding style. Instead, think of particular scenarios:
passing a 512MB object to function. Think behind the scenes, from the
stack and heap to the physical linking and build of the program.

From memory standpoint there is no difference. Assuming the address of
the reference and pointer are coming from the same location, I don't
believe there are additional instructions to set up the stack;
however, as soon as I say that, someone will cite some implementation
where it does.

The 'efficiency' is in the recipient. That is, it does not have to
check if a reference is null - since a reference can never be null.
Finally, I suspect if you declare a pointer parameter as 'void*', you
lose type-checking efficiency, or incur type-checking inefficiency
depending on your point-of-view.
 
S

spekyuman

I propose that we ban the word "efficient" from newsgroup posts unless
the poster has benchmarked and shown that the micro-optimization he
wants actually may do something.

Alright, these methods perform the same exact tasks. In each case,
what will the cost in overhead be? Both implementations refer to an
object indirectly, which allows each method to make internal
modifications. Assume the object is referring to intelligence
photography or uncompressed video. Compare this with the an
inefficient implementation, what background details can you construct?

// SIZEOF(pObject) => 4 bytes
// SIZEOF(pObject) => 500 * 2^20 bytes
void function(myObject* pObject)
{
...
}

// SIZEOF(refObject) => 500 * 2^20 bytes
void function(myObject& refObject)
{
...
}

// Inefficient Implementation
myObject function(myObject copy)
{
...
return copy;
}
 
S

spekyuman

No way to tell. It's all platform-specific. If the implementation uses
pointers behind the scenes, there's likely little difference.

If it's important, profile. If not, then use the construct that most
clearly represents the intent of the program.

Brian

Are you suggesting this is compiler specific?
 
S

spekyuman

the reference and pointer are coming from the same location, I don't
believe there are additional instructions to set up the stack;
however, as soon as I say that, someone will cite some implementation
where it does.

The 'efficiency' is in the recipient. That is, it does not have to
check if a reference is null - since a reference can never be null.
Finally, I suspect if you declare a pointer parameter as 'void*', you
lose type-checking efficiency, or incur type-checking inefficiency
depending on your point-of-view.

Alright, these methods perform the same exact tasks. In each case,
what will the cost in overhead be? Both implementations refer to an
object indirectly, which allows each method to make internal
modifications. Assume the object is referring to intelligence
photography or uncompressed video. Compare this with the an
inefficient implementation, what background details can you construct?

// SIZEOF(pObject) => 4 bytes
// SIZEOF(pObject) => 500 * 2^20 bytes
void function(myObject* pObject)
{
...
}

// SIZEOF(refObject) => 500 * 2^20 bytes
void function(myObject& refObject)
{
...
}

// Inefficient Implementation
myObject function(myObject copy)
{
...
return copy;
}
 
B

bnonaj

Pointer and reference arguments provide C++ programmers with the
ability to modify objects. What is more efficient, passing arguments
via pointer or reference? Avoid the stereotypical urge of debating
effective coding style. Instead, think of particular scenarios:
passing a 512MB object to function. Think behind the scenes, from the
stack and heap to the physical linking and build of the program.

Passing by reference automatically assumes only one object, whereas a
pointer may be to part of an array.


void someFnc1(MyObj &inp)
{
inp.doSomething();
inp[1].doSomething(); // This is plain wrong
}

void someFnc2(MyObj *inp)
{
inp->doSomething();
inp[1].doSomething(); // This is valid but maybe wrong and could
cause hard to debug problems
}

As for efficiency, I doubt with modern optimising compilers you would
find one more efficient than the other.

JB
 
J

James Kanze

I propose that we ban the word "efficient" from newsgroup posts unless
the poster has benchmarked and shown that the micro-optimization he
wants actually may do something.

I totally disagree. Programmer efficiency is very important,
and should only be compromized when absolutely essential. (Most
of the time, of course, we're really concerned with long term
programmer efficiency. We'll invest some additional effort up
front to make the inevitable maintenance easier.)
 
M

Michael DOUBEZ

gpuchtel a écrit :
Pointer and reference arguments provide C++ programmers with the
ability to modify objects. What is more efficient, passing arguments
via pointer or reference? Avoid the stereotypical urge of debating
effective coding style. Instead, think of particular scenarios:
passing a 512MB object to function. Think behind the scenes, from the
stack and heap to the physical linking and build of the program. [snip]

The 'efficiency' is in the recipient. That is, it does not have to
check if a reference is null - since a reference can never be null.

A reference can be NULL or invalid all the same. The difference is that
the code indicates a NULL wouldn't be expected (i.e. the code is self
explaining; whereas with pointer, you would have to read the doc/comments).

AFAIK the following code is valid (though UB):

void print(int& i)
{
cout<<&i<<endl;
}

int main()
{
print(*static_cast<int*>(0));

return 0;
}

And prints '0'.

Michael
 
G

gpuchtel

AFAIK the following code is valid (though UB):

void print(int& i)
{
cout<<&i<<endl;

}

int main()
{
print(*static_cast<int*>(0));

return 0;

}

And prints '0'.

Michael

A reference cannot be 'null'. What you did created a tempory int
variable that was initialized to 0 (zero), then a reference to that
temporary variable was passed to the print function, which in turn
printed '0'.
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

Alright, these methods perform the same exact tasks. In each case,
what will the cost in overhead be? Both implementations refer to an
object indirectly, which allows each method to make internal
modifications. Assume the object is referring to intelligence
photography or uncompressed video. Compare this with the an
inefficient implementation, what background details can you construct?

// SIZEOF(pObject) => 4 bytes

I assume you meant SIZEOF(myObject*)
// SIZEOF(pObject) => 500 * 2^20 bytes

SIZEOF(myObject), by the way, what's wrong with sizeof()?
void function(myObject* pObject)
{
...
}

// SIZEOF(refObject) => 500 * 2^20 bytes
void function(myObject& refObject)
{
...
}

If myObject is that large it probably means that function() won't be
called to often, so whatever the overhead of the call is, it will be
insignificant to the total running time of the program, you should focus
your energy on trying to optimise the algorithm that works on the data
instead.

I know this might not be the answer you want, but as others have pointed
out there is no one true answer since it depends on a lot of things,
such as how the compiler implements references, what other optimizations
can be made (inlining etc.) and so on.

Write your program with as clear code as possible, then run it with some
representative test data, if it is to slow then profile it and improve
on the slowest parts (and I can guarantee you, unless you have a very
strange design, it will not be the call overhead). Doing anything else
will just waste your time.
 
M

Michael DOUBEZ

gpuchtel a écrit :
A reference cannot be 'null'. What you did created a tempory int
variable that was initialized to 0 (zero), then a reference to that
temporary variable was passed to the print function, which in turn
printed '0'.

Where did you get that from ? Even if I wanted it, I couldn't pass a
temporary because the ref is not const.

It is perhaps more understandable if you replace by:
int *ptr=NULL;
print(*ptr)

and add in print
++i; //cause segfault;

Michael
 
S

spekyuman

I assume you meant SIZEOF(myObject*)


SIZEOF(myObject), by the way, what's wrong with sizeof()?



If myObject is that large it probably means that function() won't be
called to often, so whatever the overhead of the call is, it will be
insignificant to the total running time of the program, you should focus
your energy on trying to optimise the algorithm that works on the data
instead.

I know this might not be the answer you want, but as others have pointed
out there is no one true answer since it depends on a lot of things,
such as how the compiler implements references, what other optimizations
can be made (inlining etc.) and so on.

Write your program with as clear code as possible, then run it with some
representative test data, if it is to slow then profile it and improve
on the slowest parts (and I can guarantee you, unless you have a very
strange design, it will not be the call overhead). Doing anything else
will just waste your time.

In research and development, writing code correctly the first time is
the objective my friend. Prematurely optimizing code and handling data
correctly are two completely different things. Ignorance in favor of
production, is the difference between an easily replacable gear and
computer scientist.
 
V

Victor Bazarov

Alright, these methods perform the same exact tasks. In each case,
what will the cost in overhead be?

The third method requires making _at least one_ copy. The overhead
of actually *calling* the third method will be the time of making the
copy of a 'myObject' object. What that is depends on the implementation
(of both the compiler and the 'myObject' class).
Both implementations refer to an
object indirectly, which allows each method to make internal
modifications. Assume the object is referring to intelligence
photography or uncompressed video.

Why does it matter what the object is "referring to"?
Compare this with the an
inefficient implementation, what background details can you construct?

What do you mean by "background details"?
// SIZEOF(pObject) => 4 bytes
// SIZEOF(pObject) => 500 * 2^20 bytes
void function(myObject* pObject)
{
...
}

// SIZEOF(refObject) => 500 * 2^20 bytes
void function(myObject& refObject)
{
...
}

// Inefficient Implementation
myObject function(myObject copy)
{
...
return copy;
}

V
 
S

spekyuman

The third method requires making _at least one_ copy. The overhead
of actually *calling* the third method will be the time of making the
copy of a 'myObject' object. What that is depends on the implementation
(of both the compiler and the 'myObject' class).


Why does it matter what the object is "referring to"?


What do you mean by "background details"?










V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask- Hide quoted text -

- Show quoted text -- Hide quoted text -

- Show quoted text -

Background Details => What processes are occurring during a function
call? How are pointers and references treated during this time? What
exactly happens to their memory and what they reference during this
particular time? You know, the good stuff...
 
S

spekyuman

The third method requires making _at least one_ copy. The overhead
of actually *calling* the third method will be the time of making the
copy of a 'myObject' object. What that is depends on the implementation
(of both the compiler and the 'myObject' class).


Why does it matter what the object is "referring to"?


What do you mean by "background details"?










V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask- Hide quoted text -

- Show quoted text -- Hide quoted text -

- Show quoted text -

Haha, I must complement your question Victor Bazarov. I included what
the object was referring to for people without imaginations. ;-)
 
G

gpuchtel

gpuchtel a écrit :







Where did you get that from ? Even if I wanted it, I couldn't pass a
temporary because the ref is not const.

It is perhaps more understandable if you replace by:
int *ptr=NULL;
print(*ptr)

and add in print
++i; //cause segfault;

Michael- Hide quoted text -

- Show quoted text -

I didn't say (or mean) 'you' would pass a temporary, I was implying
what the compiler will do (pass). Simply stated, there is no such
thing as a 'null' reference. All your example does is to create a
reference to a (tempory) int value that contains the value of zero.
Your example of a null pointer is not relevant to the discussion of
the (im)possibility of having a 'null' reference.
 
T

Thomas J. Gritzan

gpuchtel said:
I didn't say (or mean) 'you' would pass a temporary, I was implying
what the compiler will do (pass). Simply stated, there is no such
thing as a 'null' reference. All your example does is to create a
reference to a (tempory) int value that contains the value of zero.
Your example of a null pointer is not relevant to the discussion of
the (im)possibility of having a 'null' reference.

You are wrong. The expression
static_cast<int*>(0)
or whatever you saw in Michael's code does not create a temporary integer.

It casts a null pointer constant into the type int*. He (Michael)
dereferenced the null pointer, passing it to a int reference.

The point is, you can have a 'null' reference, but you can't have one
without invoking undefined behaviour.
 
V

Victor Bazarov

gpuchtel said:
I didn't say (or mean) 'you' would pass a temporary, I was implying
what the compiler will do (pass). Simply stated, there is no such
thing as a 'null' reference. All your example does is to create a
reference to a (tempory) int value that contains the value of zero.

No temporary of type 'int' exists (or created) in the expression

static_cast<int*>(0)

The compiler should see the _integer_literal_ 0 and the static_cast
to a pointer type, and should create a *null pointer value* (of type
'int*', a pointer to int). It's all done in compile time.
Your example of a null pointer is not relevant to the discussion of
the (im)possibility of having a 'null' reference.

Why isn't it? As shown, the example is essentially the same as

...
int *p = 0;
print(*p); // no static cast needed
...

IIRC, most recent proposed corrections to the Standard actually allow
creation of a "null reference" provided that the contents of the
referred object are never evaluated (no lvalue-to-rvalue conversion
is performed). Taking address of that reference (using the operator
& on it) should yield a null pointer.

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,528
Members
45,000
Latest member
MurrayKeync

Latest Threads

Top