6

When I read litb answer to this question, I learned that passing an array by reference allows us to obtain its size. I just played little bit with code, and tried to pass a "function" by reference and surprisingly (at least for me), this code compiles:

void execute( void (&func)() ) // func is passed by reference!
{
    func();
}

Is there any difference between the last function, and this one:

void execute( void (*func)() ) // func is passed by pointer!
{
    func();
}

I tried it using VC2008, and it produces different output in each case. The strange thing is that the compiler optimizes the code better in case of a function pointer:

void print()
{
    std::cout << "Hello References!";
}
void execute( void (&func)() ) // optimized
{
    func();
}
int main()
{
    00291020  call   print (291000h)
}
=========================================
// In this case, the compiler removes all function calls in the code!
void print() // optimized!
{
    std::cout << "Hello Pointers!";
}
void execute( void (*func)() ) // optimized
{
    func();
}
int main()
{
    002F1005  push  offset string "Hello References!" (2F2124h) 
    002F100A  push  eax  
    002F100B  call  std::operator<<<std::char_traits<char> > (2F1150h) 
}

There has to be a difference, although I don't see it, right?

Note: the code was compiled using VC2008, with /O2 and /Ot turned on.


EDIT:: I am really interested about any difference between function references and function pointers. I examined the produced assembly code just to see how it is translated in each case.

Community
  • 1
  • 1
Khaled Alshaya
  • 94,250
  • 39
  • 176
  • 234
  • are you just interested in the optimizers behavior or in general function-reference information? – Johannes Schaub - litb Oct 04 '09 at 19:37
  • @litb I am actually surprised that I could pass a function by reference. It would be great if you have an explanation about the difference in functionality or other aspects from function pointers :) – Khaled Alshaya Oct 04 '09 at 19:51

4 Answers4

3

It's not as common an idiom, so it might just be that the VS team didn't add a rule to optimise it.

Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171
3

I think it is due to the C++ Standard 4.3:

An lvalue of function type T can be converted to an rvalue of type “pointer to T.” The result is a pointer to the function.

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
  • Interesting quote. Doesn't that mean after converting the function reference, basically the same code should be produced in both cases. I know this is an implementation detail, but how could the compiler optimize the pointer and not the reference(if it is converted)? – Khaled Alshaya Oct 04 '09 at 18:31
3

For the language difference (keeping only the function declarations below, since that's what's important only)

void execute( void (&func)() );

void g();
int main() {
  void (*fp)() = g;
  execute(fp); // doesn't work
  execute(&g); // doesn't work either
  execute(g); // works
}

It doesn't work, because it wants a function, not a function pointer. For the same reason that array answer rejects a pointer, this rejects a pointer too. You have to pass "g" directly.

For templates, it matters too

template<typename T>
void execute(T &t) { T u = t; u(); }

template<typename T>
void execute(T t) { T u = t; u(); }

Those two are very different from one another. If you call it with execute(g); like above, then the first will try to declare a function and initialize it with t (reference to g). The generated function would look like this

void execute(void(&t)()) { void u() = t; u(); }

Now you can initialize references and pointers to functions, but of course not functions itself. In the second definition, T will be deduced to a function pointer type by template argument deduction, and passing a function will convert it to that pointer parameter type implicitly. So everything will go fine.


I don't know why MSVC treats them differently for inlining - but i also suspect it's because function references appear more seldom.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
-2

The difference between a reference(&) and pointer(*) is that the reference provides the address of the variable or the location, and the pointer points to the location in memory of the address stored in it.

int *pointer;
int variable;

pointer = &variable; // assigning the address of variable to pointer 

variable = 53;  // value of variable

cout << *pointer; // This should output the value of the address where is pointing, in this
                  //  case 53, that is the value of variable to where is pointing.

We can conclude that the (&variable) have the address of that memory location and *anyname points to the address stored in its memory...

thkala
  • 84,049
  • 23
  • 157
  • 201
KJP
  • 531
  • 2
  • 9
  • 19
  • _"the reference provides the address of the variable or the location, and the pointer points to the location in memory of the address stored in it."_ huh ... I think you're confusing references for the address-of operator. – Lightness Races in Orbit Apr 20 '15 at 19:12