C++ – Difference Between Reference and Pointer Explained

c++pointersreference

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.

Best Answer

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.